From 321c5da9984b882c0ae93441de5b4a53cd7875ec Mon Sep 17 00:00:00 2001 From: SnapOtter Date: Fri, 8 May 2026 20:47:05 +0800 Subject: [PATCH] fix: menu bar dropdown transparent background, move test to e2e-editor - Replace bg-popover with bg-card for dropdown backgrounds (popover CSS variable is not defined in this project's theme) - Move menu bar test to tests/e2e-editor/ and adapt for editorPage fixture - Fix click-outside test to handle welcome screen overlay --- .../src/components/editor/editor-menu-bar.tsx | 4 +- .../editor-menubar.spec.ts} | 92 +++++++++---------- 2 files changed, 47 insertions(+), 49 deletions(-) rename tests/{e2e/gui-editor-menubar.spec.ts => e2e-editor/editor-menubar.spec.ts} (81%) diff --git a/apps/web/src/components/editor/editor-menu-bar.tsx b/apps/web/src/components/editor/editor-menu-bar.tsx index 2a4e8119..427497ba 100644 --- a/apps/web/src/components/editor/editor-menu-bar.tsx +++ b/apps/web/src/components/editor/editor-menu-bar.tsx @@ -389,7 +389,7 @@ function MenuItemRow({ item, onClose }: { item: MenuItem; onClose: () => void }) {submenuOpen && (
{openMenu === menu.testId && (
diff --git a/tests/e2e/gui-editor-menubar.spec.ts b/tests/e2e-editor/editor-menubar.spec.ts similarity index 81% rename from tests/e2e/gui-editor-menubar.spec.ts rename to tests/e2e-editor/editor-menubar.spec.ts index f315e005..61221f29 100644 --- a/tests/e2e/gui-editor-menubar.spec.ts +++ b/tests/e2e-editor/editor-menubar.spec.ts @@ -1,24 +1,23 @@ -import { expect, getTestImagePath, test } from "./helpers"; +import { expect, test } from "./helpers"; test.describe("Editor Menu Bar", () => { - test.beforeEach(async ({ page }) => { - await page.goto("/editor"); + test.beforeEach(async ({ editorPage: page }) => { await page.waitForSelector('[data-testid="editor-menu-bar"]', { timeout: 10_000 }); }); - test("renders all 7 top-level menus", async ({ page }) => { + test("renders all 7 top-level menus", async ({ editorPage: page }) => { for (const id of ["file", "edit", "image", "layer", "select", "filter", "view"]) { await expect(page.locator(`[data-testid="menu-${id}"]`)).toBeVisible(); } }); - test("menu bar has correct height and styling", async ({ page }) => { + test("menu bar has correct height and styling", async ({ editorPage: page }) => { const bar = page.locator('[data-testid="editor-menu-bar"]'); await expect(bar).toHaveClass(/h-7/); await expect(bar).toHaveClass(/bg-card/); }); - test("File menu opens on click and shows items", async ({ page }) => { + test("File menu opens on click and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); const dropdown = page.locator('[data-testid="menu-dropdown-file"]'); await expect(dropdown).toBeVisible(); @@ -29,13 +28,13 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-close"]')).toBeVisible(); }); - test("File > New opens new document dialog", async ({ page }) => { + test("File > New opens new document dialog", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await page.click('[data-testid="menu-item-new"]'); await expect(page.getByText("New Document").first()).toBeVisible({ timeout: 3000 }); }); - test("File > Open triggers file chooser", async ({ page }) => { + test("File > Open triggers file chooser", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); const fileChooserPromise = page.waitForEvent("filechooser"); await page.click('[data-testid="menu-item-open"]'); @@ -43,13 +42,13 @@ test.describe("Editor Menu Bar", () => { expect(chooser).toBeTruthy(); }); - test("File > Close is disabled when no image loaded", async ({ page }) => { + test("File > Close is disabled when no image loaded", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); const closeBtn = page.locator('[data-testid="menu-item-close"]'); await expect(closeBtn).toBeDisabled(); }); - test("Edit menu opens and shows items", async ({ page }) => { + test("Edit menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-edit"]'); await expect(page.locator('[data-testid="menu-dropdown-edit"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-undo"]')).toBeVisible(); @@ -61,12 +60,12 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-free-transform"]')).toBeVisible(); }); - test("Edit > Delete is disabled when no objects selected", async ({ page }) => { + test("Edit > Delete is disabled when no objects selected", async ({ editorPage: page }) => { await page.click('[data-testid="menu-edit"]'); await expect(page.locator('[data-testid="menu-item-delete"]')).toBeDisabled(); }); - test("Edit > Transform submenu renders", async ({ page }) => { + test("Edit > Transform submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-edit"]'); const transform = page.locator('[data-testid="menu-item-transform"]'); await expect(transform).toBeVisible(); @@ -77,7 +76,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-flip-vertical"]')).toBeVisible(); }); - test("Image menu opens and shows items", async ({ page }) => { + test("Image menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-image"]'); await expect(page.locator('[data-testid="menu-dropdown-image"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-image-size"]')).toBeVisible(); @@ -87,7 +86,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-adjustments"]')).toBeVisible(); }); - test("Image > Image Rotation submenu renders", async ({ page }) => { + test("Image > Image Rotation submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-image"]'); await page.locator('[data-testid="menu-item-image-rotation"]').hover(); await expect(page.locator('[data-testid="menu-item-90-cw"]')).toBeVisible({ timeout: 3000 }); @@ -95,7 +94,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-180"]')).toBeVisible(); }); - test("Image > Adjustments submenu renders", async ({ page }) => { + test("Image > Adjustments submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-image"]'); await page.locator('[data-testid="menu-item-adjustments"]').hover(); await expect(page.locator('[data-testid="menu-item-brightness-contrast"]')).toBeVisible({ @@ -104,7 +103,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-hue-saturation"]')).toBeVisible(); }); - test("Layer menu opens and shows items", async ({ page }) => { + test("Layer menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-layer"]'); await expect(page.locator('[data-testid="menu-dropdown-layer"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-new-layer"]')).toBeVisible(); @@ -115,12 +114,12 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-flatten-image"]')).toBeVisible(); }); - test("Layer > Delete Layer is disabled with single layer", async ({ page }) => { + test("Layer > Delete Layer is disabled with single layer", async ({ editorPage: page }) => { await page.click('[data-testid="menu-layer"]'); await expect(page.locator('[data-testid="menu-item-delete-layer"]')).toBeDisabled(); }); - test("Layer > Arrange submenu renders", async ({ page }) => { + test("Layer > Arrange submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-layer"]'); await page.locator('[data-testid="menu-item-arrange"]').hover(); await expect(page.locator('[data-testid="menu-item-bring-to-front"]')).toBeVisible({ @@ -129,7 +128,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-send-to-back"]')).toBeVisible(); }); - test("Select menu opens and shows items", async ({ page }) => { + test("Select menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-select"]'); await expect(page.locator('[data-testid="menu-dropdown-select"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-all"]')).toBeVisible(); @@ -138,7 +137,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-color-range"]')).toBeVisible(); }); - test("Filter menu opens and shows items", async ({ page }) => { + test("Filter menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-filter"]'); await expect(page.locator('[data-testid="menu-dropdown-filter"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-blur"]')).toBeVisible(); @@ -151,7 +150,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-invert"]')).toBeVisible(); }); - test("Filter > Blur submenu renders", async ({ page }) => { + test("Filter > Blur submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-filter"]'); await page.locator('[data-testid="menu-item-blur"]').hover(); await expect(page.locator('[data-testid="menu-item-gaussian-blur"]')).toBeVisible({ @@ -160,7 +159,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-motion-blur"]')).toBeVisible(); }); - test("Filter > Stylize submenu renders", async ({ page }) => { + test("Filter > Stylize submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-filter"]'); await page.locator('[data-testid="menu-item-stylize"]').hover(); await expect(page.locator('[data-testid="menu-item-emboss"]')).toBeVisible({ timeout: 3000 }); @@ -168,7 +167,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-posterize"]')).toBeVisible(); }); - test("Filter > Noise submenu renders", async ({ page }) => { + test("Filter > Noise submenu renders", async ({ editorPage: page }) => { await page.click('[data-testid="menu-filter"]'); await page.locator('[data-testid="menu-item-noise"]').hover(); await expect(page.locator('[data-testid="menu-item-add-noise"]')).toBeVisible({ @@ -176,7 +175,7 @@ test.describe("Editor Menu Bar", () => { }); }); - test("View menu opens and shows items", async ({ page }) => { + test("View menu opens and shows items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-view"]'); await expect(page.locator('[data-testid="menu-dropdown-view"]')).toBeVisible(); await expect(page.locator('[data-testid="menu-item-zoom-in"]')).toBeVisible(); @@ -190,7 +189,7 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-item-panels"]')).toBeVisible(); }); - test("View > Rulers toggles checkmark", async ({ page }) => { + test("View > Rulers toggles checkmark", async ({ editorPage: page }) => { await page.click('[data-testid="menu-view"]'); await page.click('[data-testid="menu-item-rulers"]'); await page.click('[data-testid="menu-view"]'); @@ -198,27 +197,27 @@ test.describe("Editor Menu Bar", () => { await expect(rulersItem.locator("svg")).toBeVisible(); }); - test("View > Grid toggles checkmark", async ({ page }) => { + test("View > Grid toggles checkmark", async ({ editorPage: page }) => { await page.click('[data-testid="menu-view"]'); await page.click('[data-testid="menu-item-grid"]'); await page.click('[data-testid="menu-view"]'); await expect(page.locator('[data-testid="menu-item-grid"]').locator("svg")).toBeVisible(); }); - test("keyboard shortcuts are displayed on menu items", async ({ page }) => { + test("keyboard shortcuts are displayed on menu items", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); const text = await page.locator('[data-testid="menu-item-new"]').textContent(); expect(text).toMatch(/N/); }); - test("clicking a menu toggles it open and closed", async ({ page }) => { + test("clicking a menu toggles it open and closed", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).toBeVisible(); await page.click('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).not.toBeVisible(); }); - test("hover switches between open menus", async ({ page }) => { + test("hover switches between open menus", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).toBeVisible(); await page.hover('[data-testid="menu-edit"]'); @@ -226,81 +225,81 @@ test.describe("Editor Menu Bar", () => { await expect(page.locator('[data-testid="menu-dropdown-file"]')).not.toBeVisible(); }); - test("clicking outside closes menu", async ({ page }) => { + test("clicking outside closes menu", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).toBeVisible(); - await page.click('[data-testid="editor-canvas"]'); + await page.locator(".flex-1.overflow-hidden").first().click({ force: true }); await expect(page.locator('[data-testid="menu-dropdown-file"]')).not.toBeVisible(); }); - test("Escape closes open menu", async ({ page }) => { + test("Escape closes open menu", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).toBeVisible(); await page.keyboard.press("Escape"); await expect(page.locator('[data-testid="menu-dropdown-file"]')).not.toBeVisible(); }); - test("hover does not open menu when none are active", async ({ page }) => { + test("hover does not open menu when none are active", async ({ editorPage: page }) => { await page.hover('[data-testid="menu-file"]'); await expect(page.locator('[data-testid="menu-dropdown-file"]')).not.toBeVisible(); }); - test("Layer > New Layer adds a layer", async ({ page }) => { + test("Layer > New Layer adds a layer", async ({ editorPage: page }) => { await page.click('[data-testid="menu-layer"]'); await page.click('[data-testid="menu-item-new-layer"]'); await page.click('[data-testid="menu-layer"]'); await expect(page.locator('[data-testid="menu-item-delete-layer"]')).toBeEnabled(); }); - test("Layer > Merge Down is disabled on bottom layer", async ({ page }) => { + test("Layer > Merge Down is disabled on bottom layer", async ({ editorPage: page }) => { await page.click('[data-testid="menu-layer"]'); await expect(page.locator('[data-testid="menu-item-merge-down"]')).toBeDisabled(); }); - test("File > Export As opens export dialog", async ({ page }) => { + test("File > Export As opens export dialog", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); await page.click('[data-testid="menu-item-export-as"]'); await expect(page.getByText("Export Image")).toBeVisible({ timeout: 3000 }); }); - test("Edit > Copy Merged is visible", async ({ page }) => { + test("Edit > Copy Merged is visible", async ({ editorPage: page }) => { await page.click('[data-testid="menu-edit"]'); await expect(page.locator('[data-testid="menu-item-copy-merged"]')).toBeVisible(); }); - test("Edit > Paste in Place is visible", async ({ page }) => { + test("Edit > Paste in Place is visible", async ({ editorPage: page }) => { await page.click('[data-testid="menu-edit"]'); await expect(page.locator('[data-testid="menu-item-paste-in-place"]')).toBeVisible(); }); - test("View > Panels toggles right panel", async ({ page }) => { + test("View > Panels toggles right panel", async ({ editorPage: page }) => { await page.click('[data-testid="menu-view"]'); await page.click('[data-testid="menu-item-panels"]'); }); - test("Image > Canvas Size opens dialog", async ({ page }) => { + test("Image > Canvas Size opens dialog", async ({ editorPage: page }) => { await page.click('[data-testid="menu-image"]'); await page.click('[data-testid="menu-item-canvas-size"]'); await expect(page.getByText("Canvas Size").first()).toBeVisible({ timeout: 3000 }); }); - test("Image > Image Size opens dialog", async ({ page }) => { + test("Image > Image Size opens dialog", async ({ editorPage: page }) => { await page.click('[data-testid="menu-image"]'); await page.click('[data-testid="menu-item-image-size"]'); await expect(page.getByText("Image Size").first()).toBeVisible({ timeout: 3000 }); }); - test("Select > Deselect does not crash", async ({ page }) => { + test("Select > Deselect does not crash", async ({ editorPage: page }) => { await page.click('[data-testid="menu-select"]'); await page.click('[data-testid="menu-item-deselect"]'); }); - test("Select > Inverse does not crash", async ({ page }) => { + test("Select > Inverse does not crash", async ({ editorPage: page }) => { await page.click('[data-testid="menu-select"]'); await page.click('[data-testid="menu-item-inverse"]'); }); - test("View > Snap toggles", async ({ page }) => { + test("View > Snap toggles", async ({ editorPage: page }) => { await page.click('[data-testid="menu-view"]'); const snapItem = page.locator('[data-testid="menu-item-snap"]'); const initialCheck = await snapItem.locator("svg").count(); @@ -314,13 +313,12 @@ test.describe("Editor Menu Bar", () => { expect(afterToggleCheck).toBe(0); }); - test("Select > All sets selection", async ({ page }) => { - const testImagePath = getTestImagePath(); + test("Select > All sets selection", async ({ editorPage: page }) => { await page.click('[data-testid="menu-file"]'); const fileChooserPromise = page.waitForEvent("filechooser"); await page.click('[data-testid="menu-item-open"]'); const chooser = await fileChooserPromise; - await chooser.setFiles(testImagePath); + await chooser.setFiles("tests/fixtures/test-200x150.png"); await page.waitForTimeout(1000); await page.click('[data-testid="menu-select"]'); await page.click('[data-testid="menu-item-all"]');