Add E2E test for transform status bar and update CSS for status bar items

This commit is contained in:
2026-04-11 03:28:47 +02:00
parent 0f65009304
commit 69336d210b
4 changed files with 74 additions and 5 deletions

View File

@@ -6484,10 +6484,10 @@ export function App({ store, initialStatusMessage }: AppProps) {
</div>
<footer className="status-bar">
<div>
<div className="status-bar__item status-bar__item--message" title={statusMessage}>
<span className="status-bar__strong">Status:</span> {statusMessage}
</div>
<div>
<div className="status-bar__item">
<span className="status-bar__strong">Spawn:</span>{" "}
{runtimeScene.spawn.source === "playerStart"
? "Authored Player Start"
@@ -10783,7 +10783,11 @@ export function App({ store, initialStatusMessage }: AppProps) {
)}
<footer className="status-bar">
<div className="status-bar__item" data-testid="status-message">
<div
className="status-bar__item status-bar__item--message"
data-testid="status-message"
title={statusMessage}
>
<span className="status-bar__strong">Status:</span> {statusMessage}
</div>
<div
@@ -10808,12 +10812,17 @@ export function App({ store, initialStatusMessage }: AppProps) {
<div
className="status-bar__item status-bar__item--asset"
data-testid="status-asset-hover"
title={hoveredAssetStatusMessage}
>
<span className="status-bar__strong">Asset:</span>{" "}
{hoveredAssetStatusMessage}
</div>
)}
<div className="status-bar__item" data-testid="status-last-command">
<div
className="status-bar__item"
data-testid="status-last-command"
title={lastCommandLabel}
>
<span className="status-bar__strong">Last:</span> {lastCommandLabel}
</div>
</footer>

View File

@@ -1222,9 +1222,10 @@ button:disabled {
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
flex-wrap: nowrap;
gap: 12px;
min-height: 36px;
height: 36px;
padding: 6px 12px;
background: rgba(18, 22, 28, 0.88);
border: 1px solid var(--color-border);
@@ -1232,13 +1233,24 @@ button:disabled {
color: var(--color-muted);
font-size: 0.8rem;
line-height: 1.2;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: thin;
}
.status-bar__item {
display: flex;
align-items: baseline;
gap: 4px;
flex: 0 0 auto;
min-width: 0;
white-space: nowrap;
}
.status-bar__item--message {
flex: 1 1 320px;
overflow: hidden;
text-overflow: ellipsis;
}
.status-bar__item--asset {
@@ -1320,6 +1332,8 @@ button:disabled {
.status-bar {
flex-direction: column;
align-items: flex-start;
height: auto;
padding: 12px 16px;
overflow: visible;
}
}

View File

@@ -375,6 +375,8 @@ Every slice should include:
- Setup: open the editor with at least one whitebox box selected in the perspective viewport.
- Steps: orbit/pan the camera away from the origin, run `G`, `R`, and `S`, then commit with click or `Enter`, cancel with `Escape`, and delete the selected target.
- Expected result: the active viewport camera keeps its exact framing and does not snap back to the world origin after commit, cancel, or delete.
- Steps: with the editor footer visible, trigger `G`, `R`, and `S`, then press `X`, `Y`, or `Z` while watching the perspective viewport bounds.
- Expected result: long transform status messages stay on one footer row, the footer height does not grow, and the viewport does not flicker or resize as the status text changes.
- Steps: start a translate or rotate session on a rotated whitebox box or rotated model instance, press `X`, `Y`, or `Z`, then press the same axis again.
- Expected result: the first press constrains to the world axis, the second press switches to the target's local axis, and unsupported local toggles surface a clear status message.
- Steps: toggle the viewport grid off and on, then pan the perspective camera far from the origin.

View File

@@ -0,0 +1,44 @@
import { expect, test } from "@playwright/test";
import { beginBoxCreation, clickViewport, getViewportPanel } from "./viewport-test-helpers";
test("transform status updates keep the footer and viewport heights stable", async ({ page }) => {
await page.setViewportSize({ width: 1024, height: 768 });
await page.goto("/");
await page.evaluate((storageKey) => {
window.localStorage.removeItem(storageKey);
}, "webeditor3d.scene-document-draft");
await page.reload();
await beginBoxCreation(page);
await clickViewport(page);
const viewportPanel = getViewportPanel(page);
const statusBar = page.locator("footer.status-bar").first();
await viewportPanel.click({ position: { x: 24, y: 24 }, force: true });
const initialViewportHeight = await viewportPanel.evaluate(
(element) => Math.round(element.getBoundingClientRect().height)
);
const initialStatusBarHeight = await statusBar.evaluate(
(element) => Math.round(element.getBoundingClientRect().height)
);
for (const key of ["G", "R", "S"]) {
await page.keyboard.press(key);
await page.keyboard.press("Z");
const nextViewportHeight = await viewportPanel.evaluate(
(element) => Math.round(element.getBoundingClientRect().height)
);
const nextStatusBarHeight = await statusBar.evaluate(
(element) => Math.round(element.getBoundingClientRect().height)
);
expect(nextViewportHeight).toBe(initialViewportHeight);
expect(nextStatusBarHeight).toBe(initialStatusBarHeight);
await page.keyboard.press("Escape");
}
});