mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
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.
106 lines
4.1 KiB
TypeScript
106 lines
4.1 KiB
TypeScript
import { createNewDocument, expect, selectTool, test } from "./helpers";
|
|
|
|
test.describe("Editor Options Bar", () => {
|
|
test.beforeEach(async ({ editorPage: page }) => {
|
|
await createNewDocument(page);
|
|
});
|
|
|
|
test("eyedropper options show sample size when eyedropper selected", async ({
|
|
editorPage: page,
|
|
}) => {
|
|
await selectTool(page, "eyedropper");
|
|
|
|
// The options bar should display the Sample label and dropdown
|
|
await expect(page.getByText("Sample:")).toBeVisible();
|
|
|
|
const sampleDropdown = page.locator("[data-testid='sample-size-dropdown']");
|
|
await expect(sampleDropdown).toBeVisible();
|
|
|
|
// Should default to "Point (1x1)"
|
|
await expect(sampleDropdown).toContainText("Point (1x1)");
|
|
|
|
// Clicking the dropdown should reveal size options
|
|
await sampleDropdown.click();
|
|
await page.waitForTimeout(300);
|
|
|
|
await expect(page.getByText("3x3 Average")).toBeVisible();
|
|
await expect(page.getByText("5x5 Average")).toBeVisible();
|
|
});
|
|
|
|
test("transform options show position/size when transform selected", async ({
|
|
editorPage: page,
|
|
}) => {
|
|
await selectTool(page, "transform");
|
|
|
|
// The options bar should show X, Y, W, H, Rotation inputs
|
|
await expect(page.locator("#transform-x")).toBeVisible();
|
|
await expect(page.locator("#transform-y")).toBeVisible();
|
|
await expect(page.locator("#transform-w")).toBeVisible();
|
|
await expect(page.locator("#transform-h")).toBeVisible();
|
|
await expect(page.locator("#transform-rotation")).toBeVisible();
|
|
|
|
// Flip buttons should be visible
|
|
await expect(page.locator("button[aria-label='Flip horizontal']")).toBeVisible();
|
|
await expect(page.locator("button[aria-label='Flip vertical']")).toBeVisible();
|
|
|
|
// Aspect ratio lock button should be visible
|
|
const lockBtn = page.locator("button[aria-label*='aspect ratio']");
|
|
await expect(lockBtn).toBeVisible();
|
|
});
|
|
|
|
test("brush options show size, opacity, hardness", async ({ editorPage: page }) => {
|
|
await selectTool(page, "brush");
|
|
|
|
const optionsBar = page.locator('[data-testid="editor-options-bar"]');
|
|
|
|
// Size, Opacity, and Hardness labels should be in the options bar
|
|
await expect(optionsBar.getByText("Size")).toBeVisible();
|
|
await expect(optionsBar.getByText("Opacity")).toBeVisible();
|
|
await expect(optionsBar.getByText("Hardness")).toBeVisible();
|
|
|
|
// Each should have a range slider and a number input
|
|
const sizeSlider = optionsBar
|
|
.locator("label")
|
|
.filter({ hasText: "Size" })
|
|
.locator("input[type='range']");
|
|
await expect(sizeSlider).toBeVisible();
|
|
|
|
const opacitySlider = optionsBar
|
|
.locator("label")
|
|
.filter({ hasText: "Opacity" })
|
|
.locator("input[type='range']");
|
|
await expect(opacitySlider).toBeVisible();
|
|
|
|
const hardnessSlider = optionsBar
|
|
.locator("label")
|
|
.filter({ hasText: "Hardness" })
|
|
.locator("input[type='range']");
|
|
await expect(hardnessSlider).toBeVisible();
|
|
});
|
|
|
|
test("selection options show mode dropdown", async ({ editorPage: page }) => {
|
|
await selectTool(page, "marquee-rect");
|
|
await page.waitForTimeout(500);
|
|
|
|
// The options bar should show Type and Mode sections
|
|
await expect(page.getByText("Type:")).toBeVisible();
|
|
await expect(page.getByText("Mode:")).toBeVisible();
|
|
|
|
// Type buttons: Rect, Ellipse, Lasso (use getByRole for robust matching)
|
|
await expect(page.getByRole("button", { name: "Rectangular" })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Elliptical" })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Lasso" }).first()).toBeVisible();
|
|
|
|
// Rect should be active since we selected marquee-rect
|
|
await expect(page.getByRole("button", { name: "Rectangular" })).toHaveAttribute(
|
|
"aria-pressed",
|
|
"true",
|
|
);
|
|
|
|
// Mode buttons: New, Add, Sub
|
|
await expect(page.getByRole("button", { name: "New Selection" })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Add to Selection" })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Subtract from Selection" })).toBeVisible();
|
|
});
|
|
});
|