Files
SnapOtter/tests/e2e-editor/editor-tools-selection.spec.ts
SnapOtter 3120e6708d fix(editor): apply layer effects + object flip, add Beta badge, repair e2e specs
While getting the editor e2e suite green, three "stale test" failures turned
out to be real bugs (per the reporter's hunch that tests might be catching
real issues):

- Layer effects (drop shadow, glows) never applied. The panel wrote effects
  into `attrs.effects` through updateObject, but the panel and renderer both
  read the object's top-level `effects`, so the toggle never persisted. Add a
  dedicated `setObjectEffects` store action and route the panel through it.
- Object flip (transform tool) did nothing. No object renderer applied
  `scaleX`/`scaleY`, and the flip negated scale without compensating position.
  Apply scale in the renderers and flip in place: mirror points for stroke
  objects, negate scale + shift position for sized objects.

(The paint-bucket / pixel-tool coordinate bug and the broken-at-non-100%-zoom
export were fixed in the preceding #259 change.)

Also adds a small "Beta" badge to the editor (welcome heading + nav link) and
repairs ~18 stale editor e2e specs whose selectors/assertions had drifted from
the current UI: the options bar is `h-9` not `h-10` (added a stable
`data-testid`), the menu bar is `h-8`/`bg-background`, the flip button
aria-labels are lowercase, the welcome "Image Editor" heading collides with an
sr-only `<h1>`, the color-picker tabs need a role-scoped selector, and the
magic-wand / flip tests now use deterministic setup and assert the actual
effect instead of fragile screenshot diffs.
2026-06-17 14:21:35 +08:00

91 lines
3.0 KiB
TypeScript

import { createNewDocument, expect, selectTool, test } from "./helpers";
test.describe("Editor Selection Tools", () => {
test.beforeEach(async ({ editorPage: page }) => {
await createNewDocument(page);
});
test("move tool activates via V shortcut", async ({ editorPage: page }) => {
// Start with a different tool
await selectTool(page, "brush");
await page.keyboard.press("v");
await page.waitForTimeout(300);
await expect(page.locator("[data-tool='move']")).toHaveAttribute("data-tool-active", "true");
});
test("move tool shows options bar label", async ({ editorPage: page }) => {
await selectTool(page, "move");
// Options bar should show "move" label
const optionsBar = page.locator('[data-testid="editor-options-bar"]');
await expect(optionsBar.getByText("move", { exact: false })).toBeVisible();
});
test("marquee activates via M shortcut", async ({ editorPage: page }) => {
await page.keyboard.press("m");
await page.waitForTimeout(300);
await expect(page.locator("[data-tool='marquee-rect']")).toHaveAttribute(
"data-tool-active",
"true",
);
});
test("marquee cycles subtypes on repeated M press", async ({ editorPage: page }) => {
await page.keyboard.press("m");
await page.waitForTimeout(300);
await expect(page.locator("[data-tool='marquee-rect']")).toHaveAttribute(
"data-tool-active",
"true",
);
// Press M again to cycle to ellipse marquee
await page.keyboard.press("m");
await page.waitForTimeout(300);
await expect(page.locator("[data-tool='marquee-rect']")).toHaveAttribute(
"data-tool-active",
"false",
);
});
test("crop activates via C shortcut", async ({ editorPage: page }) => {
await page.keyboard.press("c");
await page.waitForTimeout(300);
await expect(page.locator("[data-tool='crop']")).toHaveAttribute("data-tool-active", "true");
});
test("crop options show aspect ratio dropdown", async ({ editorPage: page }) => {
await selectTool(page, "crop");
// Crop options bar should have aspect ratio dropdown
const ratioLabel = page.getByText("Ratio:");
await expect(ratioLabel).toBeVisible();
const ratioSelect = page.locator("#crop-aspect");
await expect(ratioSelect).toBeVisible();
// The dropdown should have a "Free" option
const freeOption = ratioSelect.locator("option", { hasText: "Free" });
await expect(freeOption).toBeAttached();
});
test("crop options show width and height inputs", async ({ editorPage: page }) => {
await selectTool(page, "crop");
await expect(page.locator("#crop-width")).toBeVisible();
await expect(page.locator("#crop-height")).toBeVisible();
});
test("crop options show apply and cancel buttons", async ({ editorPage: page }) => {
await selectTool(page, "crop");
await expect(page.locator("button[aria-label='Apply crop']")).toBeVisible();
await expect(page.locator("button[aria-label='Cancel crop']")).toBeVisible();
});
});