Skip to content

Commit 44fe3dd

Browse files
gyngclaude
andcommitted
Update E2E specs for the redesigned workbench UI
The workbench redesign changed the UI contract the browser E2E suite asserts against. Update the specs to match: - Navigate via the sidebar "Workflow steps" tab strip (renamed from the toolbar "Workbench tasks and layout" nav). - Replace the removed "Adjust" step with "Compose"; the merged Compose step now shows the stage list and active-stage inspector together, so visibility expectations were flipped accordingly. - Drop the removed "Step N of 5" task-context banner assertions; assert the active tab's aria-current instead. - Rewrite the onboarding test to cover the "Browse looks…" button that now opens the look library from Compose. - Drive the theme via the new Settings theme <select> instead of the removed "Rainy Day theme" checkbox. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0519527 commit 44fe3dd

8 files changed

Lines changed: 31 additions & 38 deletions

test/e2e/app.advanced.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ test("advanced timing, audio, history, and command workflows remain coherent", a
3737
await audio.getByRole("button", { name: "Clear" }).click();
3838
await expect(audio).toBeHidden();
3939

40-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
40+
await page.getByRole("button", { name: "Compose", exact: true }).click();
4141
const grayscale = page.getByRole("checkbox", { name: /Pre-convert to grayscale/ });
4242
await grayscale.check();
4343
await page.getByRole("button", { name: "Undo" }).click();

test/e2e/app.workflow.spec.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ test("core application workflows remain operable together", async ({ page }) =>
5454
await page.getByRole("button", { name: "Apply Chain" }).click();
5555
await expect(page.getByText(/output is current|Auto apply on · output updates as you edit/)).toBeVisible();
5656

57-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
57+
await page.getByRole("button", { name: "Compose", exact: true }).click();
5858
await page.getByLabel("Pre-convert to grayscale").check();
5959
await page.getByLabel("Gamma-correct input").check();
6060
await page.getByRole("button", { name: "Source", exact: true }).click();
@@ -96,7 +96,7 @@ test("core application workflows remain operable together", async ({ page }) =>
9696
}
9797
await page.getByRole("button", { name: "Source", exact: true }).click();
9898
await page.getByRole("button", { name: "Compose", exact: true }).click();
99-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
99+
await page.getByRole("button", { name: "Compose", exact: true }).click();
100100
await page.getByRole("button", { name: "Preview", exact: true }).click();
101101

102102
await page.getByRole("button", { name: "Export…", exact: true }).click();
@@ -107,11 +107,16 @@ test("core application workflows remain operable together", async ({ page }) =>
107107
await page.getByTitle("Close").click();
108108

109109
await page.getByText("Settings", { exact: true }).click();
110-
for (const name of ["Apply automatically", "WASM acceleration", "WebGL acceleration", "Rainy Day theme"]) {
110+
for (const name of ["Apply automatically", "WASM acceleration", "WebGL acceleration"]) {
111111
const checkbox = page.getByRole("checkbox", { name });
112112
await checkbox.click();
113113
await checkbox.click();
114114
}
115+
const themeSelect = page.getByTitle("Choose a UI theme");
116+
await themeSelect.selectOption("rainy-day");
117+
await expect(page.locator("html")).toHaveAttribute("data-theme", "rainy-day");
118+
await themeSelect.selectOption("default");
119+
await expect(page.locator("html")).not.toHaveAttribute("data-theme", /.+/);
115120

116121
await page.getByRole("button", { name: "Source", exact: true }).click();
117122
await page.locator("#test-video-select").selectOption({ label: "akiyo.mp4" });

test/e2e/control-inputs.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ const replaceActiveFilter = async (page: Page, name: string) => {
1919
const result = page.getByTestId("filter-typeahead-item").filter({ hasText: name }).first();
2020
await expect(result).toBeVisible();
2121
await result.click();
22-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
22+
await page.getByRole("button", { name: "Compose", exact: true }).click();
2323
await expect(page.getByLabel("Active filter parameters")).toContainText(name);
2424
};
2525

2626
test("generated filter inputs validate, reveal dependencies, reset, and persist edits", async ({ page }) => {
2727
const pageErrors: string[] = [];
2828
page.on("pageerror", (error) => pageErrors.push(error.message));
2929
await page.goto("/?testMedia=image%3Apepper.png");
30-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
30+
await page.getByRole("button", { name: "Compose", exact: true }).click();
3131

3232
const inspector = page.getByLabel("Active filter parameters");
3333
const scanOrder = inspector.getByRole("combobox", { name: "Scan Order" });

test/e2e/library-discovery.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ test("library filters, capabilities, favorites, live options, and presets stay c
4646
await details.getByRole("button", { name: "Add to Chain" }).click();
4747
await expect(page.getByRole("listbox", { name: "Filter chain" }).getByRole("option")).toHaveCount(2);
4848
await details.getByRole("button", { name: "Close" }).click();
49-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
49+
await page.getByRole("button", { name: "Compose", exact: true }).click();
5050
await expect(page.getByLabel("Active filter parameters").getByRole("checkbox", { name: "invert R" })).not.toBeChecked();
5151

5252
await page.getByRole("button", { name: "Compose", exact: true }).click();

test/e2e/project-state.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ test("chain keyboard editing, recovery, saved chains, JSON, and share URLs round
7272
expect(JSON.parse(exportedJson)).toBeTruthy();
7373
await exportDialog.getByRole("button", { name: "OK" }).click();
7474

75-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
75+
await page.getByRole("button", { name: "Compose", exact: true }).click();
7676
const grayscale = page.getByRole("checkbox", { name: /Pre-convert to grayscale/ });
7777
await grayscale.check();
7878
await page.getByRole("button", { name: "Import", exact: true }).click();

test/e2e/ux-workbench.spec.ts

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,15 @@ test.beforeEach(async ({ page }) => {
88
});
99
});
1010

11-
test("onboarding starts from the loaded sample and opens the look library", async ({ page }) => {
11+
test("browse looks opens the look library from the compose step", async ({ page }) => {
1212
await startBrowserCoverage(page);
13-
await page.addInitScript(() => {
14-
localStorage.removeItem("ditherer-onboarding-complete");
15-
});
1613
await page.setViewportSize({ width: 1440, height: 1000 });
1714
await page.goto("/");
1815

19-
const onboarding = page.getByRole("complementary", { name: "Getting started" });
20-
await expect(onboarding).toContainText("Ready to remix");
21-
await expect(onboarding).toContainText("sample video and starter dither are already running");
22-
await expect(onboarding.getByRole("button", { name: "Browse looks" })).toBeVisible();
23-
await expect(onboarding.getByRole("button", { name: "Use my media" })).toBeVisible();
24-
await expect(onboarding.getByRole("button", { name: "Try an example" })).toHaveCount(0);
25-
26-
await onboarding.getByRole("button", { name: "Browse looks" }).click();
27-
await expect(onboarding).toBeHidden();
16+
await page.getByRole("button", { name: "Compose", exact: true }).click();
17+
const browseLooks = page.getByRole("button", { name: /Browse looks/ });
18+
await expect(browseLooks).toBeVisible();
19+
await browseLooks.click();
2820
await expect(page.getByTestId("filter-library-dialog")).toBeVisible();
2921
await writeBrowserCoverage(page, "ux-onboarding");
3022
});
@@ -101,7 +93,7 @@ test("docks canvases, compares output, and restores modal focus", async ({ page
10193
await expect(outputWindow).toBeVisible();
10294
await expect(page.locator("#source-task")).toBeVisible();
10395
await expect(page.locator("#compose-task")).toBeHidden();
104-
await expect(page.getByRole("region", { name: "Choose source media" })).toContainText("Step 1 of 5");
96+
await expect(page.getByRole("button", { name: "Source", exact: true })).toHaveAttribute("aria-current", "page");
10597

10698
await page.getByRole("button", { name: "Compose", exact: true }).click();
10799
await page.waitForTimeout(400);
@@ -112,9 +104,10 @@ test("docks canvases, compares output, and restores modal focus", async ({ page
112104
const chainComposer = page.locator("#chain-composer");
113105
await expect(chainComposer.getByText("Filter chain", { exact: true })).toBeVisible();
114106
await expect(page.locator("#source-task")).toBeHidden();
115-
await expect(page.locator("#active-filter-options")).toBeHidden();
107+
// Compose now shows the stage list and the active-stage inspector together.
108+
await expect(page.locator("#active-filter-options")).toBeVisible();
116109
await expect(page.locator("#preview-output-settings")).toBeHidden();
117-
await expect(page.getByRole("region", { name: "Build the filter chain" })).toContainText("Step 2 of 5");
110+
await expect(page.getByRole("button", { name: "Compose", exact: true })).toHaveAttribute("aria-current", "page");
118111
await expect(chainComposer.getByText("1 stage", { exact: true })).toBeVisible();
119112
const activeStage = chainComposer.locator('[data-stage-active="true"]');
120113
await expect(activeStage).toHaveCount(1);
@@ -144,10 +137,9 @@ test("docks canvases, compares output, and restores modal focus", async ({ page
144137
expect(outputBox).not.toBeNull();
145138
expect(inputBox!.x + inputBox!.width <= outputBox!.x || outputBox!.x + outputBox!.width <= inputBox!.x).toBe(true);
146139

147-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
148-
await expect(chainComposer).toBeHidden();
140+
// Adjust merged into Compose: the inspector is already visible here.
141+
await expect(chainComposer).toBeVisible();
149142
await expect(page.locator("#active-filter-options")).toBeVisible();
150-
await expect(page.getByRole("region", { name: "Tune the active stage" })).toContainText("Step 3 of 5");
151143
expect(await page.evaluate(() => window.scrollY)).toBe(0);
152144
await expect(inputWindow).toBeInViewport();
153145
await expect(outputWindow).toBeInViewport();
@@ -164,7 +156,7 @@ test("docks canvases, compares output, and restores modal focus", async ({ page
164156
await page.getByRole("button", { name: "Preview", exact: true }).click();
165157
await expect(page.locator("#compose-task")).toBeHidden();
166158
await expect(page.locator("#preview-output-settings")).toBeVisible();
167-
await expect(page.getByRole("region", { name: "Review the output" })).toContainText("Step 4 of 5");
159+
await expect(page.getByRole("button", { name: "Preview", exact: true })).toHaveAttribute("aria-current", "page");
168160
expect(await page.evaluate(() => window.scrollY)).toBe(0);
169161
await expect(inputWindow).toBeInViewport();
170162
await expect(outputWindow).toBeInViewport();
@@ -216,7 +208,7 @@ test("uses one focused mobile task and keeps library actions reachable", async (
216208
await expect(page.locator("#compose-task")).toBeHidden();
217209

218210
await page.getByRole("button", { name: "Preview", exact: true }).click();
219-
const taskNavBox = await page.getByRole("navigation", { name: "Workbench tasks and layout" }).boundingBox();
211+
const taskNavBox = await page.getByRole("navigation", { name: "Workflow steps" }).boundingBox();
220212
const previewTitleBox = await page.getByText(/^Output - /).boundingBox();
221213
expect(taskNavBox).not.toBeNull();
222214
expect(previewTitleBox).not.toBeNull();
@@ -227,7 +219,7 @@ test("uses one focused mobile task and keeps library actions reachable", async (
227219
await expect(page.locator("#source-task")).toBeHidden();
228220
await expect(page.locator("#compose-task")).toBeVisible();
229221
await expect(page.locator("#chain-composer")).toBeVisible();
230-
await expect(page.locator("#active-filter-options")).toBeHidden();
222+
await expect(page.locator("#active-filter-options")).toBeVisible();
231223
await expect(page.locator("#chain-composer").getByText("Runs top to bottom")).toBeVisible();
232224

233225
await page.getByRole("combobox", { name: "Add filter...", exact: true }).click();
@@ -244,8 +236,7 @@ test("uses one focused mobile task and keeps library actions reachable", async (
244236
expect(typeaheadItemBox!.height).toBeGreaterThanOrEqual(60);
245237
await page.keyboard.press("Escape");
246238

247-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
248-
await expect(page.locator("#chain-composer")).toBeHidden();
239+
await expect(page.locator("#chain-composer")).toBeVisible();
249240
await expect(page.locator("#active-filter-options")).toBeVisible();
250241
const inspector = page.getByLabel("Active filter parameters");
251242
await expect(inspector).toContainText("Stage 1 of 1 · Parameters");
@@ -288,7 +279,7 @@ test("keeps the compact workbench focused and its touch targets reachable", asyn
288279

289280
await expect(page.locator("#source-task")).toBeVisible();
290281
await expect(page.locator("main [role='presentation']").first()).toBeHidden();
291-
const taskNav = page.getByRole("navigation", { name: "Workbench tasks and layout" });
282+
const taskNav = page.getByRole("navigation", { name: "Workflow steps" });
292283
const taskNavBox = await taskNav.boundingBox();
293284
expect(taskNavBox).not.toBeNull();
294285
expect(taskNavBox!.height).toBeLessThanOrEqual(60);
@@ -355,7 +346,6 @@ test("keeps desktop chrome within the viewport and canvas actions on one row", a
355346
expect(box!.height).toBeGreaterThanOrEqual(24);
356347
}
357348

358-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
359349
const swatchBox = await page.getByRole("button", { name: /^Remove palette color 1,/ }).boundingBox();
360350
const extractBox = await page.getByRole("button", { name: /Extract from input/ }).boundingBox();
361351
expect(swatchBox).not.toBeNull();
@@ -391,8 +381,6 @@ test("uses touch-sized source, section, and preview controls on phones", async (
391381

392382
await page.getByRole("button", { name: "Compose", exact: true }).click();
393383
await expectTouchSize(page.getByRole("combobox", { name: "Add filter...", exact: true }));
394-
395-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
396384
await expectTouchSize(page.getByRole("button", { name: "Play / Stop" }));
397385
await expectTouchSize(page.getByRole("button", { name: /^Remove palette color 1,/ }));
398386

test/e2e/webmcp.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ test("discovers and drives Ditherer through the current WebMCP API", async ({ pa
6363
expect(result.serpentineBefore).toBe(true);
6464
expect(result.serpentineAfter).toBe(false);
6565

66-
await page.getByRole("button", { name: "Adjust", exact: true }).click();
66+
await page.getByRole("button", { name: "Compose", exact: true }).click();
6767
const serpentineControl = page.locator("#active-filter-options label")
6868
.filter({ hasText: "Serpentine" })
6969
.locator('input[type="checkbox"]');

test/e2e/workspace-layout.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ test("floating windows, comparison, fullscreen modes, and theme persistence work
7878
await page.evaluate(() => document.exitFullscreen());
7979

8080
await page.getByRole("button", { name: /Settings/ }).click();
81-
await page.getByRole("checkbox", { name: "Rainy Day theme" }).check();
81+
await page.getByTitle("Choose a UI theme").selectOption("rainy-day");
8282
await expect(page.locator("html")).toHaveAttribute("data-theme", "rainy-day");
8383
await page.reload();
8484
await expect(page.locator("html")).toHaveAttribute("data-theme", "rainy-day");

0 commit comments

Comments
 (0)