test(e2e): modernize stale routes for 2.0 section URLs (#347)

The e2e specs predate the 2.0 section-route migration and navigated to
single-segment tool URLs (/resize) that now 404 (App.tsx only mounts
/:section/:toolId). This broke the whole e2e suite (Cross-Browser, Device
Matrix, E2E Full, Visual) - part of the known stale-spec backlog.

- Sweep 929 goto("/<tool>") -> goto("/<section>/<tool>") across 45 spec
  files, using the authoritative TOOLS + toolSection() mapping. Two-segment
  routes, top-level routes (/automate, /editor, ...), and intentional 404
  tests (/nonexistent-*) are untouched.
- Implement the legacy redirects the specs already assert: the 1.x color
  tools (brightness-contrast, saturation, color-channels, color-effects)
  redirect to /image/adjust-colors (App.tsx). Good for old bookmarks too.
- Remove the analytics-consent page tests (gui-navigation + gui-visual);
  #336 deleted that page.

Mechanical + biome-clean + web typecheck passes. Browser-specific behavior
can only be confirmed by the nightly e2e jobs.
This commit is contained in:
SnapOtter
2026-06-24 20:19:37 +08:00
committed by GitHub
parent 3dd0ebb49d
commit 0f98f60c33
46 changed files with 947 additions and 969 deletions
+18
View File
@@ -187,6 +187,24 @@ export function App() {
<Route path="/files" element={<FilesPage />} />
<Route path="/privacy" element={<PrivacyPolicyPage />} />
<Route path="/editor" element={<EditorPage />} />
{/* Legacy 1.x color tools were consolidated into adjust-colors;
redirect old bookmarks to the section route. */}
<Route
path="/brightness-contrast"
element={<Navigate to="/image/adjust-colors" replace />}
/>
<Route
path="/saturation"
element={<Navigate to="/image/adjust-colors" replace />}
/>
<Route
path="/color-channels"
element={<Navigate to="/image/adjust-colors" replace />}
/>
<Route
path="/color-effects"
element={<Navigate to="/image/adjust-colors" replace />}
/>
<Route path="/:section/:toolId" element={<ToolPage />} />
<Route path="/" element={<HomePage />} />
<Route path="*" element={<NotFoundPage />} />
+10 -10
View File
@@ -16,7 +16,7 @@ async function uploadFile(page: import("@playwright/test").Page, filePath: strin
test.describe("AI Canvas Expand", () => {
test("standalone /ai-canvas-expand route loads", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await expect(page.getByText("Tool not found")).not.toBeVisible();
await expect(page.getByText("AI Canvas Expand")).toBeVisible();
@@ -25,21 +25,21 @@ test.describe("AI Canvas Expand", () => {
});
test("standalone submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await expect(page.getByTestId("ai-canvas-expand-submit")).toBeDisabled();
});
test("standalone submit disabled when all extensions are zero", async ({
loggedInPage: page,
}) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await uploadFile(page, fixturePath("test-200x150.png"));
await expect(page.getByTestId("ai-canvas-expand-submit")).toBeDisabled();
});
test("standalone submit enables with extension set", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await uploadFile(page, fixturePath("test-200x150.png"));
await page.locator("#cac-top").fill("50");
@@ -48,7 +48,7 @@ test.describe("AI Canvas Expand", () => {
});
test("standalone aspect ratio preset fills extension values", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await uploadFile(page, fixturePath("test-200x150.png"));
await page.waitForTimeout(500);
@@ -65,7 +65,7 @@ test.describe("AI Canvas Expand", () => {
});
test("standalone shows new size display", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await uploadFile(page, fixturePath("test-200x150.png"));
await page.waitForTimeout(500);
@@ -76,7 +76,7 @@ test.describe("AI Canvas Expand", () => {
});
test("tier buttons render with Balanced selected by default", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await expect(page.getByTestId("tier-fast")).toBeVisible();
await expect(page.getByTestId("tier-balanced")).toBeVisible();
@@ -87,7 +87,7 @@ test.describe("AI Canvas Expand", () => {
});
test("clicking tier button changes selection", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await page.getByTestId("tier-fast").click();
await expect(page.getByTestId("tier-fast")).toHaveClass(/bg-primary/);
@@ -97,7 +97,7 @@ test.describe("AI Canvas Expand", () => {
});
test("tier description updates on selection", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
await expect(page.getByText("Good quality, moderate speed")).toBeVisible();
@@ -108,7 +108,7 @@ test.describe("AI Canvas Expand", () => {
// ── Processing (requires AI sidecar) ────────────────────────────────
test("processes image (AI sidecar required)", async ({ loggedInPage: page }) => {
await page.goto("/ai-canvas-expand");
await page.goto("/image/ai-canvas-expand");
if (!(await isAiSidecarRunning(page))) {
test.skip(true, "AI sidecar not running");
+1 -1
View File
@@ -110,7 +110,7 @@ test.describe("Favicon download button", () => {
test("favicon shows download button instead of auto-downloading", async ({
loggedInPage: page,
}) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
// Upload a test image
const fileChooserPromise = page.waitForEvent("filechooser");
+18 -18
View File
@@ -6,12 +6,12 @@ import { expect, test, uploadTestImage } from "./helpers";
test.describe("Beautify Screenshot", () => {
test("renders tool page with settings", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Beautify Screenshot").first()).toBeVisible();
});
test("uploads image and shows preview", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -20,7 +20,7 @@ test.describe("Beautify Screenshot", () => {
});
test("shows preset cards", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
// Quick Presets section is open by default
await expect(page.getByText("Quick Presets").first()).toBeVisible();
@@ -30,7 +30,7 @@ test.describe("Beautify Screenshot", () => {
});
test("shows background, frame, spacing, and shadow sections", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Background").first()).toBeVisible();
await expect(page.getByText("Device Frame").first()).toBeVisible();
@@ -39,14 +39,14 @@ test.describe("Beautify Screenshot", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await expect(page.getByTestId("beautify-submit")).toBeVisible();
});
test("processes image with default settings", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1500);
@@ -64,7 +64,7 @@ test.describe("Beautify Screenshot", () => {
});
test("applies preset and processes", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1500);
@@ -97,7 +97,7 @@ test.describe("Beautify Screenshot", () => {
// ---------------------------------------------------------------------------
test("live preview shows gradient background on wrapper", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -109,7 +109,7 @@ test.describe("Beautify Screenshot", () => {
});
test("live preview renders macOS frame chrome", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -118,7 +118,7 @@ test.describe("Beautify Screenshot", () => {
});
test("switching to Windows frame shows Windows title bar", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -130,7 +130,7 @@ test.describe("Beautify Screenshot", () => {
});
test("switching to Browser frame shows tab bar and URL bar", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -141,7 +141,7 @@ test.describe("Beautify Screenshot", () => {
});
test("switching to None frame removes frame preview", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -159,7 +159,7 @@ test.describe("Beautify Screenshot", () => {
});
test("device frame shows label indicator", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -170,7 +170,7 @@ test.describe("Beautify Screenshot", () => {
});
test("custom shadow values reflect in preview", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -189,7 +189,7 @@ test.describe("Beautify Screenshot", () => {
});
test("watermark text appears in preview overlay", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -212,7 +212,7 @@ test.describe("Beautify Screenshot", () => {
test("image stays visible for every preset (no zero-height collapse)", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -241,7 +241,7 @@ test.describe("Beautify Screenshot", () => {
test("image stays visible when watermark is added without a frame", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -270,7 +270,7 @@ test.describe("Beautify Screenshot", () => {
test("image stays visible when watermark is added with a frame", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.waitForTimeout(1000);
+1 -1
View File
@@ -16,7 +16,7 @@ async function uploadFile(page: import("@playwright/test").Page, filePath: strin
test.describe("Blur Faces tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
try {
await page.getByTestId("blur-faces-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+2 -2
View File
@@ -4,7 +4,7 @@ import { expect, test, uploadTestImage, waitForProcessing } from "./helpers";
test.describe("Color Blindness Simulation tool", () => {
test("upload -> simulate -> download cycle", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await expect(page.getByText("Color Blindness Simulation").first()).toBeVisible();
await uploadTestImage(page);
@@ -39,7 +39,7 @@ test.describe("Color Blindness Simulation tool", () => {
});
test("shows type description when selection changes", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
const dropdown = page.locator("#cb-simulation-type");
+1 -1
View File
@@ -21,7 +21,7 @@ async function colorizeAndWait(page: import("@playwright/test").Page) {
test.describe("Colorize tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/colorize");
await page.goto("/image/colorize");
try {
await page.getByTestId("colorize-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+14 -14
View File
@@ -36,7 +36,7 @@ test.describe("Content-Aware Resize", () => {
test("direct /content-aware-resize route loads tool page (regression #131)", async ({
loggedInPage: page,
}) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
// Must NOT show "Tool not found"
await expect(page.getByText("Tool not found")).not.toBeVisible();
@@ -50,12 +50,12 @@ test.describe("Content-Aware Resize", () => {
});
test("direct route submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await expect(page.getByTestId("content-aware-resize-submit")).toBeDisabled();
});
test("direct route submit enables with width and file", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadFile(page, fixturePath("test-200x150.png"));
const widthInput = page.locator("input[placeholder='Auto']").first();
@@ -65,7 +65,7 @@ test.describe("Content-Aware Resize", () => {
});
test("content-aware toggle reveals seam carving controls", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.getByText("Content-aware")).toBeVisible();
@@ -85,7 +85,7 @@ test.describe("Content-Aware Resize", () => {
test("standard resize tabs hidden when content-aware is active", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Standard tabs visible before toggle
await expect(page.getByRole("button", { name: "Custom" })).toBeVisible();
@@ -97,14 +97,14 @@ test.describe("Content-Aware Resize", () => {
});
test("submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await expect(page.getByTestId("resize-submit")).toBeDisabled();
});
test("submit disabled without dimensions or square mode", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await uploadFile(page, fixturePath("test-200x150.png"));
@@ -118,7 +118,7 @@ test.describe("Content-Aware Resize", () => {
});
test("submit enables with width specified", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await uploadFile(page, fixturePath("test-200x150.png"));
@@ -129,7 +129,7 @@ test.describe("Content-Aware Resize", () => {
});
test("submit enables with square mode checked", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await uploadFile(page, fixturePath("test-200x150.png"));
@@ -139,7 +139,7 @@ test.describe("Content-Aware Resize", () => {
});
test("square mode disables width and height inputs", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await page.getByText("Resize to square").click();
@@ -152,7 +152,7 @@ test.describe("Content-Aware Resize", () => {
});
test("smoothing slider has correct range", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
const slider = page.locator("#blur-radius");
@@ -161,7 +161,7 @@ test.describe("Content-Aware Resize", () => {
});
test("edge sensitivity slider has correct range", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
const slider = page.locator("#sobel-threshold");
@@ -170,7 +170,7 @@ test.describe("Content-Aware Resize", () => {
});
test("PNG - content-aware resize processes and shows result", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await uploadFile(page, fixturePath("test-200x150.png"));
@@ -187,7 +187,7 @@ test.describe("Content-Aware Resize", () => {
});
test("HEIC input with content-aware resize", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await enableContentAware(page);
await uploadFile(page, fixturePath("test-200x150.heic"));
+2 -2
View File
@@ -14,7 +14,7 @@ test.describe("Document display mode (rotate-pdf)", () => {
test("uploads a PDF, rotates it, and shows the document canvas with processed result", async ({
loggedInPage: page,
}) => {
await page.goto("/rotate-pdf");
await page.goto("/pdf/rotate-pdf");
// Upload test-3page.pdf via file chooser
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -48,7 +48,7 @@ test.describe("Document display mode (rotate-pdf)", () => {
test("document viewer shows page navigation for multi-page PDF", async ({
loggedInPage: page,
}) => {
await page.goto("/rotate-pdf");
await page.goto("/pdf/rotate-pdf");
// Upload test-3page.pdf
const fileChooserPromise = page.waitForEvent("filechooser");
+1 -1
View File
@@ -21,7 +21,7 @@ async function enhanceFacesAndWait(page: import("@playwright/test").Page) {
test.describe("Enhance Faces tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
try {
await page.getByTestId("enhance-faces-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+29 -29
View File
@@ -13,7 +13,7 @@ test.describe("Semantic HTML - Landmarks", () => {
});
test("tool page has exactly one main landmark", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.locator("main")).toHaveCount(1);
});
@@ -22,7 +22,7 @@ test.describe("Semantic HTML - Landmarks", () => {
});
test("tool page has a sidebar landmark (aside)", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.locator("aside")).toBeVisible();
});
});
@@ -57,7 +57,7 @@ test.describe("Semantic HTML - Buttons", () => {
});
test("all visible buttons on tool page have accessible names", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const buttons = page.getByRole("button");
@@ -111,7 +111,7 @@ test.describe("Semantic HTML - Form Inputs", () => {
test.describe("Semantic HTML - Form Inputs on Tool Pages", () => {
test("QR generate form inputs have associated labels", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
// The URL input should be findable by its label
@@ -160,7 +160,7 @@ test.describe("Heading Hierarchy - Tool Pages", () => {
test("tool page has headings including an h2 for the tool name", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// The tool page should have an h2 heading for the tool name
@@ -309,7 +309,7 @@ test.describe("Dropzone Accessibility", () => {
loggedInPage: page,
}) => {
// Navigate to a tool page to ensure the dropzone is present
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// The upload button is a real <button> element, so it's natively
@@ -333,7 +333,7 @@ test.describe("Dropzone Accessibility", () => {
// ---------------------------------------------------------------------------
test.describe("Slider Keyboard Accessibility", () => {
test("QR size slider responds to arrow keys", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -537,7 +537,7 @@ test.describe("Image Accessibility", () => {
test("all visible images on tool page have alt text or aria-label", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const images = page.locator("img");
@@ -587,7 +587,7 @@ test.describe("No Duplicate IDs", () => {
});
test("tool page has no duplicate element IDs", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const duplicates = await page.evaluate(() => {
@@ -872,7 +872,7 @@ test.describe("Focus After Login", () => {
test.describe("Focus After File Upload", () => {
test("after file upload, focus moves toward settings panel", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// After upload, the settings panel and process button should be visible
@@ -886,7 +886,7 @@ test.describe("Focus After File Upload", () => {
});
test("after processing completes, download link is reachable", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -1077,7 +1077,7 @@ test.describe("Slider ARIA Attributes", () => {
test("QR size slider has min, max, and current value attributes", async ({
loggedInPage: page,
}) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -1096,7 +1096,7 @@ test.describe("Slider ARIA Attributes", () => {
});
test("compress quality slider has type=range with min/max", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
const slider = page.locator("input[type='range']").first();
@@ -1117,7 +1117,7 @@ test.describe("Slider ARIA Attributes", () => {
// ---------------------------------------------------------------------------
test.describe("Dropzone Keyboard Activation", () => {
test("Space key on upload button triggers file dialog", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
const uploadBtn = page.getByText("Upload from computer");
@@ -1143,7 +1143,7 @@ test.describe("Dropzone Keyboard Activation", () => {
});
test("Enter key on upload button triggers file dialog", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
const uploadBtn = page.getByText("Upload from computer");
@@ -1169,7 +1169,7 @@ test.describe("Dropzone Keyboard Activation", () => {
// ---------------------------------------------------------------------------
test.describe("Navigation Active Indicator", () => {
test("active sidebar tool link is visually distinguishable", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// The sidebar should have an active/highlighted link for the current tool
@@ -1448,7 +1448,7 @@ test.describe("Skip-to-Content Link", () => {
});
test("skip-to-content link is present on tool pages", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// Tab to first focusable element
@@ -1683,7 +1683,7 @@ test.describe("Comprehensive Color Contrast", () => {
});
test("tool page text elements meet WCAG AA contrast", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const failures = await page.evaluate(
@@ -1777,7 +1777,7 @@ test.describe("Comprehensive Color Contrast", () => {
// ---------------------------------------------------------------------------
test.describe("Tab Order", () => {
test("tab order on tool page follows logical layout", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Collect the positions of focused elements during Tab traversal
@@ -2081,7 +2081,7 @@ test.describe("All Inputs Have Labels", () => {
test("all visible inputs on tool page have associated labels or aria-label", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const unlabelledInputs = await page.evaluate(() => {
@@ -2132,7 +2132,7 @@ test.describe("All Inputs Have Labels", () => {
// ---------------------------------------------------------------------------
test.describe("Dropzone Visual Feedback", () => {
test("dropzone has descriptive text for screen readers", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// The dropzone section should have descriptive text
@@ -2151,7 +2151,7 @@ test.describe("Dropzone Visual Feedback", () => {
// ---------------------------------------------------------------------------
test.describe("Slider Keyboard Accessibility - Extended", () => {
test("QR size slider responds to ArrowLeft to decrease value", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -2171,7 +2171,7 @@ test.describe("Slider Keyboard Accessibility - Extended", () => {
});
test("slider Home key jumps to minimum value", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -2187,7 +2187,7 @@ test.describe("Slider Keyboard Accessibility - Extended", () => {
});
test("slider End key jumps to maximum value", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -2263,7 +2263,7 @@ test.describe("Navigation Keyboard - Extended", () => {
// ---------------------------------------------------------------------------
test.describe("QR Generate Page Input Accessibility", () => {
test("QR generate page size slider has associated label", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const sizeSlider = page.locator("#qr-size");
@@ -2334,7 +2334,7 @@ test.describe("ARIA Live Regions", () => {
test("processing status changes are announced via live region", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Check for any aria-live regions on the page
@@ -2364,7 +2364,7 @@ test.describe("ARIA Live Regions", () => {
// ---------------------------------------------------------------------------
test.describe("Image Accessibility - QR Generate", () => {
test("QR preview image has alt text after generation", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
// Enter data to generate QR
@@ -2401,7 +2401,7 @@ test.describe("Image Accessibility - QR Generate", () => {
// ---------------------------------------------------------------------------
test.describe("Color Contrast - Tool Page Dark Theme", () => {
test("tool page meets WCAG AA contrast in dark theme", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Switch to dark theme
@@ -2573,7 +2573,7 @@ test.describe("Tabindex Values", () => {
});
test("no positive tabindex values on tool page", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const positiveTabindexElements = await page.evaluate(() => {
+28 -28
View File
@@ -21,7 +21,7 @@ test.describe("Multi-file upload", () => {
test("upload 2 files via file chooser and both appear in Files section", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -37,7 +37,7 @@ test.describe("Multi-file upload", () => {
test("upload 3+ files and all are listed with filenames and sizes", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -55,7 +55,7 @@ test.describe("Multi-file upload", () => {
});
test("'+ Add more' adds files to existing set", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload initial file
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -79,7 +79,7 @@ test.describe("Multi-file upload", () => {
});
test("'Clear all' removes all files and returns to dropzone", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload files
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -101,7 +101,7 @@ test.describe("Multi-file upload", () => {
test("ThumbnailStrip shows at bottom with clickable thumbnails", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -124,7 +124,7 @@ test.describe("Multi-file upload", () => {
});
test("Previous/Next arrows cycle through images", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -163,7 +163,7 @@ test.describe("Multi-file upload", () => {
});
test("counter badge shows N/M format", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -177,7 +177,7 @@ test.describe("Multi-file upload", () => {
});
test("upload 5 files and all are listed", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload initial 3 files
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -204,7 +204,7 @@ test.describe("Multi-file upload", () => {
});
test("upload 5 files shows count with filenames and sizes", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload initial 3 files
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -237,7 +237,7 @@ test.describe("Multi-file upload", () => {
});
test("upload 3+ files via drag-and-drop and all appear", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -268,7 +268,7 @@ test.describe("Multi-file upload", () => {
});
test("selecting thumbnail updates main viewer image", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -310,7 +310,7 @@ test.describe("Batch processing", () => {
test("upload 3 images, process resize, all 3 results available", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 3 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -339,7 +339,7 @@ test.describe("Batch processing", () => {
});
test("'Download All' button visible for batch results", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload multiple images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -366,7 +366,7 @@ test.describe("Batch processing", () => {
});
test("navigate through batch results with Previous/Next", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -401,7 +401,7 @@ test.describe("Batch processing", () => {
});
test("each batch result has download link", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -445,7 +445,7 @@ test.describe("Batch processing", () => {
});
test("spinner appears during batch processing", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -480,7 +480,7 @@ test.describe("Batch processing", () => {
});
test("'Download All' triggers ZIP download", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -512,7 +512,7 @@ test.describe("Batch processing", () => {
});
test("undo on one image does not affect others", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -551,7 +551,7 @@ test.describe("Batch processing", () => {
test("per-image undo isolation: undoing image 1 preserves image 2 result", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -616,7 +616,7 @@ test.describe("Mixed formats", () => {
test("upload JPEG + PNG + WebP and all are accepted and shown", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -638,7 +638,7 @@ test.describe("Mixed formats", () => {
});
test("mixed JPEG + PNG + WebP batch processes correctly", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -679,7 +679,7 @@ test.describe("Mixed formats", () => {
test("upload JPEG + PNG + WebP + HEIC mixed batch and all are accepted", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
const fileChooserPromise = page.waitForEvent("filechooser");
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -707,7 +707,7 @@ test.describe("Mixed formats", () => {
// ---------------------------------------------------------------------------
test.describe("Batch processing - Compress tool", () => {
test("batch compress 2 images with quality mode", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -742,7 +742,7 @@ test.describe("Batch processing - Compress tool", () => {
});
test("batch compress 3 images and Download All ZIP available", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
// Upload 3 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -773,7 +773,7 @@ test.describe("Batch processing - Compress tool", () => {
test.describe("Batch processing - Convert tool", () => {
test("batch convert 2 images to WebP format", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -804,7 +804,7 @@ test.describe("Batch processing - Convert tool", () => {
});
test("batch convert 3 images and all results navigable", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
// Upload 3 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -842,7 +842,7 @@ test.describe("Batch processing - Convert tool", () => {
test.describe("Batch processing - Rotate tool", () => {
test("batch rotate 2 images by 90 degrees", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
// Upload 2 images
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -879,7 +879,7 @@ test.describe("Batch processing - Rotate tool", () => {
test("batch rotate 3 images with flip and Download All available", async ({
loggedInPage: page,
}) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
// Upload 3 images
const fileChooserPromise = page.waitForEvent("filechooser");
+6 -6
View File
@@ -28,7 +28,7 @@ test.describe("Format upload and resize processing", () => {
];
for (const [label, fileName] of formats) {
test(`${label} uploads and resizes`, async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFixture(page, fixtureFormat(fileName));
await page.locator("input[placeholder='Auto']").first().fill("25");
await page.getByRole("button", { name: "Resize" }).click();
@@ -39,7 +39,7 @@ test.describe("Format upload and resize processing", () => {
});
}
test("HEIC uploads and resizes", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFixture(page, fixtureImage("test-200x150.heic"));
await page.locator("input[placeholder='Auto']").first().fill("25");
await page.getByRole("button", { name: "Resize" }).click();
@@ -54,7 +54,7 @@ test.describe("Convert tool - new output formats", () => {
test.describe.configure({ timeout: 60_000 });
for (const fmt of ["bmp", "ico", "jp2", "qoi", "jxl"]) {
test(`converts PNG to ${fmt.toUpperCase()}`, async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", fmt);
await page.getByRole("button", { name: /convert/i }).click();
@@ -80,7 +80,7 @@ test.describe("Convert tool - new output formats", () => {
test.describe("Convert tool - format dropdown", () => {
test("contains all 13 output formats", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await page.waitForSelector("#convert-target-format", { timeout: 10_000 });
const options = await page
.locator("#convert-target-format option")
@@ -108,7 +108,7 @@ test.describe("Convert tool - format dropdown", () => {
test.describe("HEIC-to-JPG conversion", () => {
test.describe.configure({ timeout: 60_000 });
test("uploads HEIC, converts to JPG", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadFixture(page, fixtureImage("test-200x150.heic"));
await expect(page.getByText(/heic/i).first()).toBeVisible({ timeout: 10_000 });
await page.selectOption("#convert-target-format", "jpg");
@@ -133,7 +133,7 @@ test.describe("Exotic format upload acceptance", () => {
];
for (const [label, fileName] of exoticFormats) {
test(`${label} uploads to info without crashing`, async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadFixture(page, fixtureFormat(fileName));
await page.getByRole("button", { name: /read info/i }).click();
await waitForProcessing(page);
+5 -5
View File
@@ -183,7 +183,7 @@ test.describe("Keyboard Shortcuts - Work From Any Page", () => {
});
test("Cmd/Ctrl+Alt+1 navigates to Resize from a tool page", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await expect(page).toHaveURL("/compress");
await page.keyboard.press(`${MOD}+Alt+1`);
@@ -278,7 +278,7 @@ test.describe("Keyboard Shortcuts - Escape Key", () => {
test.describe("Keyboard Shortcuts - Textarea Suppression", () => {
test("Cmd/Ctrl+/ does not navigate when focused on textarea", async ({ loggedInPage: page }) => {
// Navigate to a tool that has a textarea (watermark-text has text input)
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
// Find a textarea or contenteditable element on the page
const textarea = page.locator("textarea").first();
@@ -296,7 +296,7 @@ test.describe("Keyboard Shortcuts - Textarea Suppression", () => {
test("Cmd/Ctrl+Shift+D does not toggle theme when focused on a textarea", async ({
loggedInPage: page,
}) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
const textarea = page.locator("textarea").first();
if (await textarea.isVisible({ timeout: 3000 }).catch(() => false)) {
@@ -395,7 +395,7 @@ test.describe("Keyboard Accessibility", () => {
// ---------------------------------------------------------------------------
test.describe("Keyboard Shortcuts - Cmd+K Cross-Page", () => {
test("Cmd/Ctrl+K focuses search on a tool page", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.keyboard.press(`${MOD}+k`);
@@ -552,7 +552,7 @@ test.describe("Keyboard Shortcuts - Rapid Sequences", () => {
});
test("Cmd/Ctrl+/ from a tool page navigates to home", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await expect(page).toHaveURL("/compress");
await page.keyboard.press(`${MOD}+/`);
+24 -24
View File
@@ -74,7 +74,7 @@ async function uploadFiles(page: import("@playwright/test").Page, files: string[
// ===========================================================================
test.describe("Multi-file upload - drag-and-drop", () => {
test("drag-and-drop 2 files onto dropzone registers both", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const dropzone = page.locator("[class*='border-dashed']").first();
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
@@ -101,7 +101,7 @@ test.describe("Multi-file upload - drag-and-drop", () => {
});
test("drag-and-drop 5 files and all appear with thumbnails", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
const dropzone = page.locator("[class*='border-dashed']").first();
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
@@ -140,7 +140,7 @@ test.describe("Multi-file upload - file info display", () => {
test("selecting each thumbnail shows correct filename in info area", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await expect(page.getByText("Files (3)")).toBeVisible();
@@ -163,7 +163,7 @@ test.describe("Multi-file upload - file info display", () => {
});
test("file size is displayed for each file when selected", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG]);
await expect(page.getByText("Files (2)")).toBeVisible();
@@ -182,7 +182,7 @@ test.describe("Multi-file upload - file info display", () => {
test("counter badge updates when files are added via Add more", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload 1 file initially
await uploadFiles(page, [FIXTURE_JPG]);
@@ -209,7 +209,7 @@ test.describe("Multi-file upload - file info display", () => {
});
test("ThumbnailStrip not shown for single file", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG]);
await expect(page.getByText("Files (1)")).toBeVisible();
@@ -221,7 +221,7 @@ test.describe("Multi-file upload - file info display", () => {
});
test("Clear all then re-upload works correctly", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Upload initial files
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG]);
@@ -248,7 +248,7 @@ test.describe("Batch processing - results verification", () => {
test("batch resize 3 images and each result has distinct download link", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await expect(page.getByText("Files (3)")).toBeVisible();
@@ -287,7 +287,7 @@ test.describe("Batch processing - results verification", () => {
test("batch process button shows correct file count for different tool", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await expect(page.getByText("Files (3)")).toBeVisible();
@@ -300,7 +300,7 @@ test.describe("Batch processing - results verification", () => {
test("batch results preserve file count after processing completes", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG]);
await expect(page.getByText("Files (2)")).toBeVisible();
@@ -319,7 +319,7 @@ test.describe("Batch processing - results verification", () => {
});
test("Download All ZIP contains correct filename", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -348,7 +348,7 @@ test.describe("Batch processing - results verification", () => {
// ===========================================================================
test.describe("Batch processing - undo behavior", () => {
test("undo after batch keeps all files loaded", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -377,7 +377,7 @@ test.describe("Batch processing - undo behavior", () => {
});
test("after undo, can re-process the batch", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG]);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -420,7 +420,7 @@ test.describe("Mixed format batch - HEIC", () => {
test("JPEG + PNG + WebP + HEIC batch process resize all successfully", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP, FIXTURE_HEIC]);
await expect(page.getByText("Files (4)")).toBeVisible();
@@ -451,7 +451,7 @@ test.describe("Mixed format batch - HEIC", () => {
test("HEIC files show thumbnails in strip alongside other formats", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_HEIC]);
await expect(page.getByText("Files (2)")).toBeVisible();
@@ -903,7 +903,7 @@ test.describe("Cross-tool file carrying - extended", () => {
loggedInPage: page,
}) => {
// Upload and process on resize
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -915,7 +915,7 @@ test.describe("Cross-tool file carrying - extended", () => {
}
// Navigate away
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
// No stale download links should leak
@@ -928,11 +928,11 @@ test.describe("Cross-tool file carrying - extended", () => {
await page.waitForLoadState("networkidle");
// Navigate to resize
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Navigate to compress
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
// Go back to resize
@@ -968,12 +968,12 @@ test.describe("Cross-tool file carrying - extended", () => {
loggedInPage: page,
}) => {
// Upload on resize
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await expect(page.getByText(/test-image/i).first()).toBeVisible();
// Navigate directly to a different tool
await page.goto("/rotate");
await page.goto("/image/rotate");
await page.waitForLoadState("networkidle");
// No stale processed state
@@ -988,7 +988,7 @@ test.describe("Multi-file navigation - edge cases", () => {
test("Previous not visible on first image, Next not visible on last", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG]);
await expect(page.getByText("1 / 2")).toBeVisible();
@@ -1013,7 +1013,7 @@ test.describe("Multi-file navigation - edge cases", () => {
test("thumbnail click updates counter badge to correct position", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
await expect(page.getByText("1 / 3")).toBeVisible();
@@ -1037,7 +1037,7 @@ test.describe("Multi-file navigation - edge cases", () => {
test("selected thumbnail has active styling (outline-primary)", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadFiles(page, [FIXTURE_JPG, FIXTURE_PNG, FIXTURE_WEBP]);
// First thumbnail should be selected by default
+10 -26
View File
@@ -372,13 +372,13 @@ test.describe("Fullscreen Grid Page", () => {
// ---------------------------------------------------------------------------
test.describe("Tool Page - Resize", () => {
test("shows tool icon and name", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.getByText("Resize").first()).toBeVisible();
});
test("shows dropzone with dashed border before upload", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
const dropzone = page.locator("[class*='border-dashed']").first();
await expect(dropzone).toBeVisible();
@@ -388,7 +388,7 @@ test.describe("Tool Page - Resize", () => {
test("after upload shows Files section, Settings section, and Process button", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Files section
@@ -507,7 +507,7 @@ test.describe("Tool Page - Settings and Process Flow", () => {
test("resize: settings panel appears after upload with process button", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
@@ -516,21 +516,21 @@ test.describe("Tool Page - Settings and Process Flow", () => {
});
test("compress: settings panel appears after upload", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
});
test("convert: settings panel appears after upload", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
});
test("resize: download link appears after processing", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Click the process button
@@ -555,7 +555,7 @@ test.describe("Tool Page - Settings and Process Flow", () => {
await page.getByRole("button", { name: /login/i }).click();
await page.waitForURL("/", { timeout: 15_000 });
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// On mobile, settings may be behind a toggle button
@@ -928,22 +928,6 @@ test.describe("Routing Edge Cases", () => {
await expect(page).toHaveURL("/");
});
test("/analytics-consent page renders consent UI", async ({ browser }) => {
// Use unauthenticated context since analytics-consent is unguarded
const context = await browser.newContext({
storageState: { cookies: [], origins: [] },
});
const page = await context.newPage();
await page.goto("/analytics-consent");
// The page shows a heading and two buttons
await expect(page.getByText("Help improve SnapOtter")).toBeVisible();
await expect(page.getByRole("button", { name: "Sure, sounds good" })).toBeVisible();
await expect(page.getByRole("button", { name: "Not right now" })).toBeVisible();
await context.close();
});
test("legacy /color-effects redirects to /adjust-colors", async ({ loggedInPage: page }) => {
await page.goto("/color-effects");
@@ -1023,7 +1007,7 @@ test.describe("Browser Back/Forward Navigation", () => {
});
test("page refresh preserves route on tool page", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page).toHaveURL("/resize");
await page.reload();
@@ -1426,7 +1410,7 @@ test.describe("Routing - Additional Edge Cases", () => {
});
test("deep-linking to a specific tool page works", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await expect(page).toHaveURL("/watermark-text");
await expect(page.getByText("Text Watermark").first()).toBeVisible();
});
+36 -36
View File
@@ -72,7 +72,7 @@ test.describe("Page Load Performance", () => {
await page.goto("about:blank");
const start = Date.now();
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
const loadTime = Date.now() - start;
@@ -88,13 +88,13 @@ test.describe("SPA Navigation Timing", () => {
loggedInPage: page,
}) => {
// Warm up by visiting the target page first so modules are cached
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.goto("/");
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const navTime = Date.now() - start;
@@ -107,7 +107,7 @@ test.describe("SPA Navigation Timing", () => {
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// Wait for the tool name to appear as a signal the route rendered
await page.locator("h2").filter({ hasText: "Resize" }).waitFor({ state: "visible" });
@@ -119,11 +119,11 @@ test.describe("SPA Navigation Timing", () => {
test("navigate from /resize to /compress completes within 2000ms", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
await page.locator("h2").filter({ hasText: "Compress" }).waitFor({ state: "visible" });
const navTime = Date.now() - start;
@@ -134,11 +134,11 @@ test.describe("SPA Navigation Timing", () => {
test("navigate from /compress to /convert completes within 2000ms", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/convert");
await page.goto("/image/convert");
await page.waitForLoadState("domcontentloaded");
await page.locator("h2").filter({ hasText: "Convert" }).waitFor({ state: "visible" });
const navTime = Date.now() - start;
@@ -301,7 +301,7 @@ test.describe("Bundle Efficiency", () => {
}
});
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// In dev mode Vite serves unbundled ESM; more requests than production.
@@ -388,7 +388,7 @@ test.describe("Repeated Operations Performance", () => {
});
test("10x upload/clear cycle stays responsive", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const timings: number[] = [];
@@ -510,17 +510,17 @@ test.describe("Performance Budgets - Route Navigation", () => {
loggedInPage: page,
}) => {
// Warm up both routes so lazy chunks are cached
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
// Now measure warmed navigation
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
await page.locator("h2").filter({ hasText: "Compress" }).waitFor({ state: "visible" });
const navTime = Date.now() - start;
@@ -531,7 +531,7 @@ test.describe("Performance Budgets - Route Navigation", () => {
test("sidebar click navigation < 500ms (warmed)", async ({ loggedInPage: page }) => {
// Warm up
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.goto("/");
await page.waitForLoadState("networkidle");
@@ -553,7 +553,7 @@ test.describe("Performance Budgets - Route Navigation", () => {
// ---------------------------------------------------------------------------
test.describe("File Upload Preview Timing", () => {
test("file upload preview renders within 1000ms", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const start = Date.now();
@@ -579,7 +579,7 @@ test.describe("Interaction Responsiveness - Live Preview", () => {
test("compress quality slider updates preview indicator promptly", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
// Look for a quality slider or range input
@@ -605,7 +605,7 @@ test.describe("Interaction Responsiveness - Live Preview", () => {
test.describe("Interaction Responsiveness - No Blank Flash", () => {
test("no white/blank flash during tool-to-tool navigation", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Monitor for blank screens during navigation
@@ -624,11 +624,11 @@ test.describe("Interaction Responsiveness - No Blank Flash", () => {
}, 50);
// Navigate through several tools
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
await page.goto("/rotate");
await page.goto("/image/rotate");
await page.waitForLoadState("domcontentloaded");
await page.goto("/convert");
await page.goto("/image/convert");
await page.waitForLoadState("domcontentloaded");
clearInterval(checkInterval);
@@ -644,7 +644,7 @@ test.describe("Interaction Responsiveness - No Blank Flash", () => {
await page.goto("about:blank");
// Navigate and immediately check for content
const response = page.goto("/resize");
const response = page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// After domcontentloaded, body should have content (either the spinner or the page)
@@ -692,7 +692,7 @@ test.describe("Interaction Responsiveness - Theme Toggle", () => {
// ---------------------------------------------------------------------------
test.describe("Performance Budgets - Lazy Load", () => {
test("tool settings lazy load < 500ms after upload", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const start = Date.now();
@@ -739,7 +739,7 @@ test.describe("DOMContentLoaded Budget - Various Pages", () => {
await page.goto("about:blank");
const start = Date.now();
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
const loadTime = Date.now() - start;
@@ -895,7 +895,7 @@ test.describe("Memory and Stability - Extended", () => {
];
// Upload on the first tool
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await expect(page.getByText(/test-image/i).first()).toBeVisible({ timeout: 5_000 });
@@ -906,7 +906,7 @@ test.describe("Memory and Stability - Extended", () => {
}
// Come back to resize -- state should be clean (no leftover from first upload)
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
// The dropzone should be visible (previous upload state was cleared on nav)
@@ -933,7 +933,7 @@ test.describe("Memory Stability - Heap Measurement", () => {
];
// Warm up and take baseline
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const baselineHeap = await page.evaluate(() => {
@@ -1005,7 +1005,7 @@ test.describe("Memory Stability - Heap Measurement", () => {
});
test("10 upload/clear cycles do not leak memory", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const baselineHeap = await page.evaluate(() => {
@@ -1166,7 +1166,7 @@ test.describe("QR Generate Page Load Budget", () => {
await page.goto("about:blank");
const start = Date.now();
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
const loadTime = Date.now() - start;
@@ -1177,7 +1177,7 @@ test.describe("QR Generate Page Load Budget", () => {
await page.goto("about:blank");
const start = Date.now();
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.locator("[data-testid='qr-input-url']").waitFor({ state: "visible" });
const renderTime = Date.now() - start;
@@ -1190,7 +1190,7 @@ test.describe("QR Generate Page Load Budget", () => {
// ---------------------------------------------------------------------------
test.describe("Processing Throughput", () => {
test("resize end-to-end processing completes within 5s", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await uploadTestImage(page);
@@ -1210,7 +1210,7 @@ test.describe("Processing Throughput", () => {
});
test("two sequential processes do not degrade in speed", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await uploadTestImage(page);
@@ -1424,7 +1424,7 @@ test.describe("Console Error Monitoring", () => {
});
await page.goto("about:blank");
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const realErrors = consoleErrors.filter(
@@ -1449,7 +1449,7 @@ test.describe("Network Request Budget", () => {
}
});
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Tool page should not make excessive API calls on load
@@ -1464,7 +1464,7 @@ test.describe("Network Request Budget", () => {
test.describe("Navigation Timing Consistency", () => {
test("sequential navigation to same page is consistent", async ({ loggedInPage: page }) => {
// Warm up
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
const timings: number[] = [];
@@ -1474,7 +1474,7 @@ test.describe("Navigation Timing Consistency", () => {
await page.waitForLoadState("networkidle");
const start = Date.now();
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
timings.push(Date.now() - start);
}
+2 -2
View File
@@ -14,7 +14,7 @@ test.describe("QA Fixes Verification", () => {
});
test("tool page loads correctly", async ({ page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// Should see resize tool content
await expect(page.locator("text=Resize").first()).toBeVisible({ timeout: 10_000 });
@@ -98,7 +98,7 @@ test.describe("QA Fixes Verification", () => {
});
test("dropzone uses i18n strings (no hardcoded 'or')", async ({ page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// The dropzone should be visible with upload button
const uploadBtn = page.locator("text=Upload").first();
+43 -43
View File
@@ -75,7 +75,7 @@ test.describe("Connection Banner & Disconnection", () => {
test("toast appears when processing fails due to disconnection", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Block all tool API requests to simulate disconnection during processing
@@ -107,7 +107,7 @@ test.describe("Connection Banner & Disconnection", () => {
});
test("no crash when attempting to process while disconnected", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Block all API tool endpoints to simulate disconnection
@@ -245,7 +245,7 @@ test.describe("File Upload Validation", () => {
test("non-image file upload (.txt) is rejected or ignored gracefully", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Create a .txt file via the file chooser
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -407,7 +407,7 @@ test.describe("Add Member Form Validation", () => {
// ---------------------------------------------------------------------------
test.describe("QR Generate Form Validation", () => {
test("download button disabled when text input is empty", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
// The download button should be disabled when no data is entered
@@ -417,7 +417,7 @@ test.describe("QR Generate Form Validation", () => {
});
test("download button enabled after entering text", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("domcontentloaded");
// Enter data in the URL field (default content type)
@@ -473,7 +473,7 @@ test.describe("Pipeline Save Form Validation", () => {
// ---------------------------------------------------------------------------
test.describe("Compress Quality Clamping", () => {
test("compress quality slider clamps to max value", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
// Find a quality slider/range input
@@ -501,7 +501,7 @@ test.describe("Compress Quality Clamping", () => {
// ---------------------------------------------------------------------------
test.describe("Tool Form Validation", () => {
test("resize process button requires a file to be uploaded", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Before uploading, the resize button should be visible but the dropzone
// should be shown instead of the process area
@@ -519,7 +519,7 @@ test.describe("Tool Form Validation", () => {
});
test("compress process button requires a file to be uploaded", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
const compressBtn = page.getByRole("button", { name: "Compress" });
const dropzone = page.locator("[class*='border-dashed']").first();
@@ -550,7 +550,7 @@ test.describe("Toast Behavior", () => {
});
test("success toast after processing auto-dismisses", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Set a width and process
@@ -579,7 +579,7 @@ test.describe("State Reset on Navigation", () => {
loggedInPage: page,
}) => {
// Upload and process in resize
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -595,7 +595,7 @@ test.describe("State Reset on Navigation", () => {
await page.waitForLoadState("networkidle");
// Come back to resize
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
// State should be clean: dropzone visible, no download link
@@ -604,7 +604,7 @@ test.describe("State Reset on Navigation", () => {
});
test("upload, clear, upload again: no orphaned state", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// First upload
await uploadTestImage(page);
@@ -697,7 +697,7 @@ test.describe("Memory and Stability", () => {
});
test("10x upload/clear cycle without crash or leak", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
for (let i = 0; i < 10; i++) {
// Upload
@@ -764,7 +764,7 @@ test.describe("Memory and Stability", () => {
});
test("10x upload/clear cycle does not leak blob URLs", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
for (let i = 0; i < 10; i++) {
await uploadTestImage(page);
@@ -791,7 +791,7 @@ test.describe("Server Error Handling", () => {
test("oversized file beyond limit shows clear error, not crash", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept to return 413 (payload too large)
@@ -822,7 +822,7 @@ test.describe("Server Error Handling", () => {
});
test("server 500 response shows error, not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept the tool API endpoint to return 500
@@ -853,7 +853,7 @@ test.describe("Server Error Handling", () => {
});
test("empty file upload (0 bytes) is handled gracefully", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Create a 0-byte file
const fs = await import("node:fs");
@@ -878,7 +878,7 @@ test.describe("Server Error Handling", () => {
});
test("server 400 response shows validation error clearly", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept to return 400 with a validation message
@@ -911,7 +911,7 @@ test.describe("Server Error Handling", () => {
test("auth expiry (401) redirects to login or shows re-auth prompt", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept to return 401 (session expired)
@@ -949,7 +949,7 @@ test.describe("Server Error Handling", () => {
});
test("rate limit (429) shows throttle message, not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept to return 429 (rate limited)
@@ -980,7 +980,7 @@ test.describe("Server Error Handling", () => {
});
test("network timeout shows error, not infinite spinner", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept and never respond -- simulates a timeout/hang
@@ -1013,7 +1013,7 @@ test.describe("Tool-Specific Form Validation", () => {
test("resize with width = 0 does not crash or submit invalid request", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Set width to 0
@@ -1037,7 +1037,7 @@ test.describe("Tool-Specific Form Validation", () => {
});
test("resize with negative width does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("-100");
@@ -1063,7 +1063,7 @@ test.describe("Toast Notifications", () => {
await page.waitForLoadState("domcontentloaded");
// Trigger a toast by processing an image
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
await page.getByRole("button", { name: "Resize" }).click();
@@ -1084,7 +1084,7 @@ test.describe("Toast Notifications", () => {
});
test("error toast appears on processing failure", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Intercept to cause a failure
@@ -1113,7 +1113,7 @@ test.describe("Toast Notifications", () => {
test("toast does not block interactive elements beneath it", async ({ loggedInPage: page }) => {
// Process to trigger a toast
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
await page.getByRole("button", { name: "Resize" }).click();
@@ -1138,7 +1138,7 @@ test.describe("Toast Notifications", () => {
});
test("success toast auto-dismisses within reasonable time", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -1165,7 +1165,7 @@ test.describe("Toast Notifications", () => {
});
test("multiple toasts stack without overlapping", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Process twice quickly to generate multiple toasts
@@ -1209,7 +1209,7 @@ test.describe("Toast Notifications", () => {
});
test("toast text is readable (has sufficient size)", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -1243,7 +1243,7 @@ test.describe("Server Error Handling - Service Unavailable", () => {
test("server 503 response shows maintenance/retry message, not crash", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.route("**/api/v1/tools/image/resize", (route) =>
@@ -1277,7 +1277,7 @@ test.describe("Resize Extreme Dimensions", () => {
test("resize with extremely large width does not crash browser", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("999999");
@@ -1293,7 +1293,7 @@ test.describe("Resize Extreme Dimensions", () => {
});
test("resize with fractional width does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50.5");
@@ -1313,7 +1313,7 @@ test.describe("Double-Click Prevention", () => {
test("rapid double-click on process button does not cause duplicate requests", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -1342,10 +1342,10 @@ test.describe("Double-Click Prevention", () => {
// ---------------------------------------------------------------------------
test.describe("Browser History Navigation", () => {
test("browser back button from tool page does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
await page.goBack();
@@ -1360,10 +1360,10 @@ test.describe("Browser History Navigation", () => {
});
test("browser forward button after back does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("domcontentloaded");
await page.goBack();
@@ -1411,7 +1411,7 @@ test.describe("Concurrent Error Recovery", () => {
test("multiple tool endpoints failing simultaneously does not crash", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Block multiple endpoints
@@ -1447,7 +1447,7 @@ test.describe("Processing State Cleanup", () => {
test("failed processing does not leave orphaned loading state", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.route("**/api/v1/tools/image/resize", (route) =>
@@ -1473,7 +1473,7 @@ test.describe("Processing State Cleanup", () => {
});
test("successful processing followed by clear resets fully", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("input[placeholder='Auto']").first().fill("50");
@@ -1504,7 +1504,7 @@ test.describe("Processing State Cleanup", () => {
// ---------------------------------------------------------------------------
test.describe("Resize Aspect Ratio Lock", () => {
test("setting only width with lock enabled does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Fill only width, leave height as Auto
@@ -1519,7 +1519,7 @@ test.describe("Resize Aspect Ratio Lock", () => {
});
test("setting only height with lock enabled does not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Fill only height (second Auto input)
@@ -1557,7 +1557,7 @@ test.describe("Settings Persistence", () => {
expect(isDarkAfterToggle).not.toBe(isDarkBefore);
// Navigate away and back
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("domcontentloaded");
const isDarkAfterNav = await page.evaluate(() =>
+113 -113
View File
@@ -16,13 +16,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Remove Background", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await expect(page.getByText("Remove Background").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows subject type buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "People" })).toBeVisible();
@@ -31,7 +31,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows quality tier buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
@@ -40,7 +40,7 @@ test.describe("GUI AI Tools", () => {
});
test("ultra quality visible only for People subject", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// People is default -- Ultra should be visible
@@ -52,7 +52,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows background type buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -67,7 +67,7 @@ test.describe("GUI AI Tools", () => {
test("color presets appear when Color background is selected", async ({
loggedInPage: page,
}) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -81,7 +81,7 @@ test.describe("GUI AI Tools", () => {
test("gradient presets appear when Gradient background is selected", async ({
loggedInPage: page,
}) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -93,7 +93,7 @@ test.describe("GUI AI Tools", () => {
});
test("effects section is collapsible", async ({ loggedInPage: page }) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// Expand Effects
@@ -105,7 +105,7 @@ test.describe("GUI AI Tools", () => {
test("submit button disabled without file, enabled with file", async ({
loggedInPage: page,
}) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
const submitBtn = page.getByTestId("remove-background-submit");
await expect(submitBtn).toBeDisabled();
@@ -117,7 +117,7 @@ test.describe("GUI AI Tools", () => {
test("image background upload button visible when Image background selected", async ({
loggedInPage: page,
}) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -129,7 +129,7 @@ test.describe("GUI AI Tools", () => {
test("switching subject type hides ultra quality for non-People", async ({
loggedInPage: page,
}) => {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
await uploadTestImage(page);
// People is default -- Ultra visible
@@ -146,13 +146,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Upscale", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await expect(page.getByText("Image Upscaling").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows scale factor buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
await expect(page.getByText("Scale Factor")).toBeVisible();
@@ -163,7 +163,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows quality tier buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
@@ -172,7 +172,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows enhance faces checkbox in non-Fast mode", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
// Balanced is default, should show face enhancement
@@ -180,21 +180,21 @@ test.describe("GUI AI Tools", () => {
});
test("shows noise reduction slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
await expect(page.getByText("Noise Reduction")).toBeVisible();
});
test("shows output format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
await expect(page.locator("#upscale-format")).toBeVisible();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
const submitBtn = page.getByTestId("upscale-submit");
await expect(submitBtn).toBeDisabled();
@@ -204,7 +204,7 @@ test.describe("GUI AI Tools", () => {
});
test("face enhance checkbox toggles", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
const checkbox = page
@@ -220,7 +220,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching to Fast hides enhance faces", async ({ loggedInPage: page }) => {
await page.goto("/upscale");
await page.goto("/image/upscale");
await uploadTestImage(page);
await page.getByRole("button", { name: "Fast" }).click();
@@ -233,13 +233,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("OCR", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await expect(page.getByText("OCR").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows quality selector buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
@@ -248,14 +248,14 @@ test.describe("GUI AI Tools", () => {
});
test("shows enhance before scanning checkbox after upload", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await uploadTestImage(page);
await expect(page.getByText("Enhance before scanning")).toBeVisible();
});
test("shows collapsible Language section after upload", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await uploadTestImage(page);
// Language section shows default "Auto-detect"
@@ -270,7 +270,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
const submitBtn = page.getByTestId("ocr-submit");
await expect(submitBtn).toBeDisabled();
@@ -281,7 +281,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows language dropdown options when expanded", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await uploadTestImage(page);
await page.getByText("Language").click();
@@ -294,7 +294,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching quality tier changes active button", async ({ loggedInPage: page }) => {
await page.goto("/ocr");
await page.goto("/image/ocr");
await uploadTestImage(page);
await page.getByRole("button", { name: "Best" }).click();
@@ -308,7 +308,7 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Blur Faces", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
await expect(page.getByText("Face").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
@@ -316,7 +316,7 @@ test.describe("GUI AI Tools", () => {
test("shows blur radius and sensitivity sliders after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
await uploadTestImage(page);
await expect(page.locator("#blur-faces-blur-radius")).toBeVisible();
@@ -331,7 +331,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
const submitBtn = page.getByTestId("blur-faces-submit");
await expect(submitBtn).toBeDisabled();
@@ -342,7 +342,7 @@ test.describe("GUI AI Tools", () => {
});
test("blur radius slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
await uploadTestImage(page);
const slider = page.locator("#blur-faces-blur-radius");
@@ -351,7 +351,7 @@ test.describe("GUI AI Tools", () => {
});
test("sensitivity slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/blur-faces");
await page.goto("/image/blur-faces");
await uploadTestImage(page);
const slider = page.locator("#blur-faces-sensitivity");
@@ -365,13 +365,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Enhance Faces", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await expect(page.getByText("Face Enhancement").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows quality tier buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Fast" })).toBeVisible();
@@ -380,7 +380,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows enhancement strength slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
await expect(page.locator("#enhance-faces-strength")).toBeVisible();
@@ -392,7 +392,7 @@ test.describe("GUI AI Tools", () => {
test("shows only enhance main face checkbox in non-Best mode", async ({
loggedInPage: page,
}) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
// Balanced is default, should show main face checkbox
@@ -404,7 +404,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows detection sensitivity slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
await expect(page.locator("#enhance-faces-sensitivity")).toBeVisible();
@@ -412,7 +412,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
const submitBtn = page.getByTestId("enhance-faces-submit");
await expect(submitBtn).toBeDisabled();
@@ -423,7 +423,7 @@ test.describe("GUI AI Tools", () => {
});
test("strength slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
const slider = page.locator("#enhance-faces-strength");
@@ -432,7 +432,7 @@ test.describe("GUI AI Tools", () => {
});
test("sensitivity slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/enhance-faces");
await page.goto("/image/enhance-faces");
await uploadTestImage(page);
const slider = page.locator("#enhance-faces-sensitivity");
@@ -446,13 +446,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Erase Object", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await expect(page.getByText("Object Eraser").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows brush size slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
await expect(page.locator("#eraser-brush-size")).toBeVisible();
@@ -462,21 +462,21 @@ test.describe("GUI AI Tools", () => {
});
test("shows output format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
await expect(page.locator("#eraser-format")).toBeVisible();
});
test("shows paint hint text after upload", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
await expect(page.getByText("Paint over the objects you want to remove")).toBeVisible();
});
test("submit disabled without strokes", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
const submitBtn = page.getByTestId("erase-object-submit");
@@ -484,7 +484,7 @@ test.describe("GUI AI Tools", () => {
});
test("brush size slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
const slider = page.locator("#eraser-brush-size");
@@ -493,7 +493,7 @@ test.describe("GUI AI Tools", () => {
});
test("output format selector has options", async ({ loggedInPage: page }) => {
await page.goto("/erase-object");
await page.goto("/image/erase-object");
await uploadTestImage(page);
const select = page.locator("#eraser-format");
@@ -509,13 +509,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Smart Crop", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await expect(page.getByText("Smart Crop").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows mode tabs after upload", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Subject Focus" })).toBeVisible();
@@ -524,7 +524,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows subject focus controls by default", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
// Strategy buttons
@@ -541,7 +541,7 @@ test.describe("GUI AI Tools", () => {
});
test("face focus mode shows framing presets", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await page.getByRole("button", { name: "Face Focus" }).click();
@@ -553,7 +553,7 @@ test.describe("GUI AI Tools", () => {
test("auto trim mode shows tolerance slider and pad to square", async ({
loggedInPage: page,
}) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await page.getByRole("button", { name: "Auto Trim" }).click();
@@ -563,7 +563,7 @@ test.describe("GUI AI Tools", () => {
});
test("social presets tab shows platform presets", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await page.getByRole("button", { name: "Social Presets" }).click();
@@ -572,7 +572,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
const submitBtn = page.getByTestId("smart-crop-submit");
await expect(submitBtn).toBeDisabled();
@@ -582,7 +582,7 @@ test.describe("GUI AI Tools", () => {
});
test("auto trim mode tolerance slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await page.getByRole("button", { name: "Auto Trim" }).click();
@@ -592,7 +592,7 @@ test.describe("GUI AI Tools", () => {
});
test("subject focus width/height inputs accept values", async ({ loggedInPage: page }) => {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
await uploadTestImage(page);
await page.locator("#sc-width").fill("800");
@@ -607,13 +607,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Colorize", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/colorize");
await page.goto("/image/colorize");
await expect(page.getByText("Colorize").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows AI model selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/colorize");
await page.goto("/image/colorize");
await uploadTestImage(page);
await expect(page.getByText("AI Model")).toBeVisible();
@@ -624,14 +624,14 @@ test.describe("GUI AI Tools", () => {
});
test("shows color intensity slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/colorize");
await page.goto("/image/colorize");
await uploadTestImage(page);
await expect(page.getByText("Color Intensity")).toBeVisible();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/colorize");
await page.goto("/image/colorize");
const submitBtn = page.getByTestId("colorize-submit");
await expect(submitBtn).toBeDisabled();
@@ -642,7 +642,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching AI model changes active button", async ({ loggedInPage: page }) => {
await page.goto("/colorize");
await page.goto("/image/colorize");
await uploadTestImage(page);
await page.locator("button").filter({ hasText: "Best" }).first().click();
@@ -655,13 +655,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Noise Removal", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await expect(page.getByText("Noise Removal").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows denoising tier buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
await expect(page.getByText("Denoising Tier")).toBeVisible();
@@ -674,7 +674,7 @@ test.describe("GUI AI Tools", () => {
test("shows strength, detail preservation, and color noise sliders after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
await expect(page.getByText("Strength").first()).toBeVisible();
@@ -683,7 +683,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows output format buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -695,7 +695,7 @@ test.describe("GUI AI Tools", () => {
});
test("quality slider appears for lossy formats", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
// Original format is default -- no quality slider
@@ -709,7 +709,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
const submitBtn = page.getByTestId("noise-removal-submit");
await expect(submitBtn).toBeDisabled();
@@ -720,7 +720,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching denoising tier changes active button", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
await page.getByRole("button", { name: "Maximum" }).click();
@@ -728,7 +728,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching to PNG hides quality slider", async ({ loggedInPage: page }) => {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -743,20 +743,20 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Passport Photo", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await expect(page.getByText("Passport Photo").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows country selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
await expect(page.getByText("Country")).toBeVisible();
});
test("shows DPI input after upload", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
await expect(page.getByText("DPI").first()).toBeVisible();
@@ -764,7 +764,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows background color options after upload", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
await expect(page.getByText("Background Color")).toBeVisible();
@@ -772,7 +772,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows max file size presets after upload", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
await expect(page.getByText("Max File Size")).toBeVisible();
@@ -782,7 +782,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows spec info bar after upload", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
// Spec bar showing dimensions info
@@ -792,7 +792,7 @@ test.describe("GUI AI Tools", () => {
test("generate button not visible before upload, shown after analysis", async ({
loggedInPage: page,
}) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
// Generate button should not exist before upload (it only appears after face analysis)
await expect(page.getByTestId("passport-photo-generate")).not.toBeVisible();
@@ -806,7 +806,7 @@ test.describe("GUI AI Tools", () => {
});
test("clicking max file size preset changes active button", async ({ loggedInPage: page }) => {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
await uploadTestImage(page);
await page.getByRole("button", { name: "50 KB" }).click();
@@ -820,7 +820,7 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Red Eye Removal", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
await expect(page.getByText("Red Eye Removal").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
@@ -828,7 +828,7 @@ test.describe("GUI AI Tools", () => {
test("shows sensitivity and correction strength sliders after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
await uploadTestImage(page);
await expect(page.getByText("Sensitivity").first()).toBeVisible();
@@ -841,7 +841,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows output format buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -853,7 +853,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
const submitBtn = page.getByTestId("red-eye-removal-submit");
await expect(submitBtn).toBeDisabled();
@@ -864,7 +864,7 @@ test.describe("GUI AI Tools", () => {
});
test("sensitivity slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
await uploadTestImage(page);
const slider = page.locator("input[type='range']").first();
@@ -872,7 +872,7 @@ test.describe("GUI AI Tools", () => {
});
test("switching output format changes active button", async ({ loggedInPage: page }) => {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -888,13 +888,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Restore Photo", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await expect(page.getByText("Photo Restoration").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows feature toggle checkboxes after upload", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
// The component was refactored from mode buttons to individual feature toggles
@@ -905,7 +905,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows feature toggles after upload", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
await expect(page.getByText("Scratch Removal")).toBeVisible();
@@ -917,7 +917,7 @@ test.describe("GUI AI Tools", () => {
test("face fidelity slider visible when face enhancement is checked", async ({
loggedInPage: page,
}) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
// Face enhancement is on by default
@@ -929,7 +929,7 @@ test.describe("GUI AI Tools", () => {
test("denoise strength slider visible when noise reduction is checked", async ({
loggedInPage: page,
}) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
// Noise reduction is on by default
@@ -937,7 +937,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
const submitBtn = page.getByTestId("restore-photo-submit");
await expect(submitBtn).toBeDisabled();
@@ -948,7 +948,7 @@ test.describe("GUI AI Tools", () => {
});
test("unchecking face enhancement hides fidelity slider", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
// Face Enhancement is on by default
@@ -965,7 +965,7 @@ test.describe("GUI AI Tools", () => {
});
test("toggling feature checkboxes works", async ({ loggedInPage: page }) => {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
await uploadTestImage(page);
// Toggle Scratch Removal off and back on
@@ -986,7 +986,7 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("PNG Transparency Fixer", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await expect(page.getByText("PNG Transparency Fixer").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
@@ -994,7 +994,7 @@ test.describe("GUI AI Tools", () => {
test("shows description text and submit button after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
await expect(page.getByText("Upload a PNG with a fake transparent background")).toBeVisible();
@@ -1003,7 +1003,7 @@ test.describe("GUI AI Tools", () => {
});
test("advanced section is collapsed by default", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
// Advanced toggle should be visible
@@ -1017,7 +1017,7 @@ test.describe("GUI AI Tools", () => {
test("advanced section toggles open with defringe and output format", async ({
loggedInPage: page,
}) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
// Open advanced section
@@ -1035,7 +1035,7 @@ test.describe("GUI AI Tools", () => {
});
test("defringe slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
// Open advanced section
@@ -1049,7 +1049,7 @@ test.describe("GUI AI Tools", () => {
});
test("output format dropdown allows switching to WebP", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
// Open advanced section
@@ -1067,7 +1067,7 @@ test.describe("GUI AI Tools", () => {
test("submit button disabled without file, enabled with file", async ({
loggedInPage: page,
}) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
const submitBtn = page.getByTestId("transparency-fixer-submit");
await expect(submitBtn).toBeDisabled();
@@ -1078,7 +1078,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows multi-file text for batch upload", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
// Upload multiple files
const fileChooserPromise = page.waitForEvent("filechooser");
await page.locator("[class*='border-dashed']").first().click();
@@ -1097,7 +1097,7 @@ test.describe("GUI AI Tools", () => {
});
test("output format dropdown has expected options", async ({ loggedInPage: page }) => {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
await uploadTestImage(page);
// Open advanced section
@@ -1116,13 +1116,13 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Content-Aware Resize", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await expect(page.getByText("Content-Aware").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows width and height inputs after upload", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await expect(page.locator("#car-width")).toBeVisible();
@@ -1130,14 +1130,14 @@ test.describe("GUI AI Tools", () => {
});
test("shows resize to square checkbox", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await expect(page.getByText("Resize to square")).toBeVisible();
});
test("square mode disables width/height inputs", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
// Check Resize to square
@@ -1152,14 +1152,14 @@ test.describe("GUI AI Tools", () => {
});
test("shows protect faces checkbox", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await expect(page.getByText("Protect faces")).toBeVisible();
});
test("shows smoothing slider", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await expect(page.locator("#car-blur-radius")).toBeVisible();
@@ -1167,7 +1167,7 @@ test.describe("GUI AI Tools", () => {
});
test("shows edge sensitivity slider", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await expect(page.locator("#car-sobel-threshold")).toBeVisible();
@@ -1175,7 +1175,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit disabled without dimensions or square mode", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
const submitBtn = page.getByTestId("content-aware-resize-submit");
@@ -1183,7 +1183,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit enabled with width set", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await page.locator("#car-width").fill("80");
@@ -1191,7 +1191,7 @@ test.describe("GUI AI Tools", () => {
});
test("submit enabled with square mode", async ({ loggedInPage: page }) => {
await page.goto("/content-aware-resize");
await page.goto("/image/content-aware-resize");
await uploadTestImage(page);
await page
@@ -1209,7 +1209,7 @@ test.describe("GUI AI Tools", () => {
// ========================================================================
test.describe("Meme Generator", () => {
test("renders tool page without standard dropzone", async ({ loggedInPage: page }) => {
await page.goto("/meme-generator");
await page.goto("/image/meme-generator");
await expect(page.getByText("Meme").first()).toBeVisible();
// Meme generator uses no-dropzone display mode
@@ -1217,14 +1217,14 @@ test.describe("GUI AI Tools", () => {
});
test("shows gallery phase with template selection prompt", async ({ loggedInPage: page }) => {
await page.goto("/meme-generator");
await page.goto("/image/meme-generator");
// Gallery phase shows template selection guidance
await expect(page.getByText(/select a template|upload your own/i).first()).toBeVisible();
});
test("shows template thumbnails in gallery", async ({ loggedInPage: page }) => {
await page.goto("/meme-generator");
await page.goto("/image/meme-generator");
// Gallery should show meme template thumbnails or an upload option
await expect(
+40 -40
View File
@@ -166,13 +166,13 @@ test.describe("GUI Color & Adjustment Tools", () => {
// ========================================================================
test.describe("Sharpening", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await expect(page.getByText("Sharpening").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows method selector with three options", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Adaptive" })).toBeVisible();
@@ -181,7 +181,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("shows presets in adaptive mode", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
// Adaptive mode is default
@@ -193,7 +193,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("noise reduction buttons visible", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "off" })).toBeVisible();
@@ -203,7 +203,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("advanced controls toggle reveals extra sliders", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await page.getByText("Advanced Controls").click();
@@ -213,7 +213,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("switching to unsharp mask shows amount slider", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await page.getByRole("button", { name: "Unsharp Mask" }).click();
@@ -221,7 +221,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("switching to high-pass shows radius slider", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await page.getByRole("button", { name: "High-Pass" }).click();
@@ -230,7 +230,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("selecting a preset enables submit", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
// Adaptive mode with Medium preset should enable submit
@@ -239,7 +239,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("processes sharpening and shows download", async ({ loggedInPage: page }) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await page.getByTestId("sharpening-submit").click();
@@ -254,13 +254,13 @@ test.describe("GUI Color & Adjustment Tools", () => {
// ========================================================================
test.describe("Color Palette", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/color-palette");
await page.goto("/image/color-palette");
await expect(page.getByText("Color Palette").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows Extract Colors button after upload", async ({ loggedInPage: page }) => {
await page.goto("/color-palette");
await page.goto("/image/color-palette");
await uploadTestImage(page);
const btn = page.getByTestId("color-palette-submit");
@@ -269,7 +269,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("submit button is enabled with file uploaded", async ({ loggedInPage: page }) => {
await page.goto("/color-palette");
await page.goto("/image/color-palette");
await uploadTestImage(page);
const submitBtn = page.getByTestId("color-palette-submit");
@@ -277,7 +277,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("extracts colors and displays palette", async ({ loggedInPage: page }) => {
await page.goto("/color-palette");
await page.goto("/image/color-palette");
await uploadTestImage(page);
await page.getByTestId("color-palette-submit").click();
@@ -288,7 +288,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("submit button text says Extract Colors", async ({ loggedInPage: page }) => {
await page.goto("/color-palette");
await page.goto("/image/color-palette");
await uploadTestImage(page);
await expect(page.getByTestId("color-palette-submit")).toHaveText(/Extract Colors/);
@@ -300,13 +300,13 @@ test.describe("GUI Color & Adjustment Tools", () => {
// ========================================================================
test.describe("Replace Color", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await expect(page.getByText("Replace").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows source and target color pickers after upload", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
await expect(page.locator("#replace-source-color")).toBeVisible();
@@ -314,7 +314,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("tolerance slider visible", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
await expect(page.locator("#replace-tolerance")).toBeVisible();
@@ -323,7 +323,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("make transparent checkbox hides target color", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
// Check Make transparent
@@ -338,7 +338,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("tolerance slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
const slider = page.locator("#replace-tolerance");
@@ -347,14 +347,14 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
await expect(page.getByTestId("replace-color-submit")).toBeVisible();
});
test("processes color replacement and shows download", async ({ loggedInPage: page }) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
await page.getByTestId("replace-color-submit").click();
@@ -369,13 +369,13 @@ test.describe("GUI Color & Adjustment Tools", () => {
// ========================================================================
test.describe("Image Enhancement", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await expect(page.getByText("Image Enhancement").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows enhancement mode and controls after upload", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
// Wait for analysis to complete
@@ -385,7 +385,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("shows all six enhancement mode buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
await expect(page.getByText("Enhancement Mode")).toBeVisible({ timeout: 10_000 });
@@ -398,7 +398,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("shows intensity slider with percentage", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
await expect(page.getByText("Intensity")).toBeVisible({ timeout: 10_000 });
@@ -408,7 +408,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("switching enhancement mode changes active button", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
await expect(page.getByText("Enhancement Mode")).toBeVisible({ timeout: 10_000 });
@@ -418,21 +418,21 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("shows Deep Enhance AI toggle", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
await expect(page.getByText("Deep Enhance (AI)")).toBeVisible({ timeout: 10_000 });
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
await expect(page.getByTestId("image-enhancement-submit")).toBeVisible({ timeout: 10_000 });
});
test("processes enhancement and shows download", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
// Wait for analysis
@@ -454,13 +454,13 @@ test.describe("GUI Color & Adjustment Tools", () => {
// ========================================================================
test.describe("Color Blindness Simulator", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await expect(page.getByText("Color Blindness").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows simulation type dropdown after upload", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
await expect(page.locator("#cb-simulation-type")).toBeVisible();
@@ -469,7 +469,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
test("dropdown has grouped options (Red-Green, Blue-Yellow, Monochromatic)", async ({
loggedInPage: page,
}) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
const select = page.locator("#cb-simulation-type");
@@ -479,7 +479,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("shows description text for selected type", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
// Default is deuteranomaly -- should show description
@@ -487,7 +487,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("changing simulation type updates description", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
await page.selectOption("#cb-simulation-type", "achromatopsia");
@@ -497,7 +497,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
test("submit button disabled without file, enabled with file", async ({
loggedInPage: page,
}) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
const submitBtn = page.getByTestId("color-blindness-submit");
await expect(submitBtn).toBeDisabled();
@@ -508,7 +508,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
});
test("processes simulation and shows download", async ({ loggedInPage: page }) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
await page.getByTestId("color-blindness-submit").click();
@@ -545,7 +545,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
test("sharpening: undo after processing returns to method selector", async ({
loggedInPage: page,
}) => {
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await uploadTestImage(page);
await page.getByTestId("sharpening-submit").click();
@@ -562,7 +562,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
test("replace-color: undo after processing returns to color pickers", async ({
loggedInPage: page,
}) => {
await page.goto("/replace-color");
await page.goto("/image/replace-color");
await uploadTestImage(page);
await page.getByTestId("replace-color-submit").click();
@@ -580,7 +580,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
test("color-blindness: undo after processing returns to type selector", async ({
loggedInPage: page,
}) => {
await page.goto("/color-blindness");
await page.goto("/image/color-blindness");
await uploadTestImage(page);
await page.getByTestId("color-blindness-submit").click();
@@ -612,7 +612,7 @@ test.describe("GUI Color & Adjustment Tools", () => {
await page.locator("#color-slider-brightness").fill("30");
await page.goto("/sharpening");
await page.goto("/image/sharpening");
await page.goto("/image/adjust-colors");
await expect(page.getByText("Upload from computer")).toBeVisible();
+69 -69
View File
@@ -12,7 +12,7 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Resize", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.getByText("Resize").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
await expect(page.getByText("Settings").first()).toBeVisible();
@@ -21,7 +21,7 @@ test.describe("GUI Essential Tools", () => {
test("shows custom size tab with width/height inputs after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Custom Size tab is active by default
@@ -33,7 +33,7 @@ test.describe("GUI Essential Tools", () => {
test("tab switching between Custom Size, Scale, and Presets", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Switch to Scale tab
@@ -54,7 +54,7 @@ test.describe("GUI Essential Tools", () => {
});
test("fit mode buttons work in custom tab", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await expect(page.getByText("Fit Mode")).toBeVisible();
@@ -67,7 +67,7 @@ test.describe("GUI Essential Tools", () => {
});
test("content-aware toggle reveals advanced options", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Toggle content-aware switch (label is a sibling span, not aria-label)
@@ -84,7 +84,7 @@ test.describe("GUI Essential Tools", () => {
test("submit disabled without dimensions, enabled with width", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Submit should be disabled without dimensions
@@ -97,7 +97,7 @@ test.describe("GUI Essential Tools", () => {
});
test("processes image and shows download link", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("50");
@@ -108,7 +108,7 @@ test.describe("GUI Essential Tools", () => {
});
test("scale tab processes image at 25%", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.getByText("Scale").click();
@@ -120,7 +120,7 @@ test.describe("GUI Essential Tools", () => {
});
test("aspect ratio link button toggles", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// The link/unlink button for aspect ratio should be visible
@@ -131,7 +131,7 @@ test.describe("GUI Essential Tools", () => {
});
test("download link has correct data-testid", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("50");
@@ -144,7 +144,7 @@ test.describe("GUI Essential Tools", () => {
});
test("width and height inputs accept numeric values", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("200");
@@ -152,7 +152,7 @@ test.describe("GUI Essential Tools", () => {
});
test("scale percentage quick buttons are interactive", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.getByText("Scale").click();
@@ -167,13 +167,13 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Crop", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await expect(page.getByText("Crop").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows aspect ratio presets after upload", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await expect(page.getByText("Aspect Ratio")).toBeVisible();
@@ -186,7 +186,7 @@ test.describe("GUI Essential Tools", () => {
});
test("shows position and size inputs after upload", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await expect(page.getByText("Position & Size")).toBeVisible();
@@ -197,7 +197,7 @@ test.describe("GUI Essential Tools", () => {
});
test("custom aspect ratio reveals input fields", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.getByRole("button", { name: "Custom" }).click();
@@ -207,14 +207,14 @@ test.describe("GUI Essential Tools", () => {
});
test("rule of thirds grid toggle", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await expect(page.getByText("Rule of Thirds")).toBeVisible();
});
test("crop submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(500);
@@ -222,7 +222,7 @@ test.describe("GUI Essential Tools", () => {
});
test("aspect ratio presets change the active button", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
// Click 1:1 aspect ratio
@@ -234,7 +234,7 @@ test.describe("GUI Essential Tools", () => {
});
test("processes crop and shows download", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -254,7 +254,7 @@ test.describe("GUI Essential Tools", () => {
test("tall portrait image (200x4000) fits within viewport without overflow", async ({
loggedInPage: page,
}) => {
await page.goto("/crop");
await page.goto("/image/crop");
const portraitPath = path.join(
process.cwd(),
@@ -286,7 +286,7 @@ test.describe("GUI Essential Tools", () => {
test("extremely tall portrait image (100x6000) fits within viewport without overflow", async ({
loggedInPage: page,
}) => {
await page.goto("/crop");
await page.goto("/image/crop");
const extremePath = path.join(
process.cwd(),
@@ -319,13 +319,13 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Rotate", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await expect(page.getByText("Rotate").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows rotate controls after upload", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
// Quick rotate buttons
@@ -335,7 +335,7 @@ test.describe("GUI Essential Tools", () => {
});
test("shows flip buttons", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await expect(page.getByText("Flip").first()).toBeVisible();
@@ -344,7 +344,7 @@ test.describe("GUI Essential Tools", () => {
});
test("shows straighten slider", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await expect(page.getByText("Straighten")).toBeVisible();
@@ -352,7 +352,7 @@ test.describe("GUI Essential Tools", () => {
});
test("angle input updates on rotate-right click", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await page.getByTestId("rotate-right").click();
@@ -364,7 +364,7 @@ test.describe("GUI Essential Tools", () => {
test("submit disabled without changes, enabled after rotation", async ({
loggedInPage: page,
}) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
// Submit should be disabled with no changes
@@ -377,7 +377,7 @@ test.describe("GUI Essential Tools", () => {
});
test("reset all changes button appears after modification", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await page.getByTestId("rotate-right").click();
@@ -385,7 +385,7 @@ test.describe("GUI Essential Tools", () => {
});
test("flip horizontal enables submit", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
const submitBtn = page.getByTestId("rotate-submit");
@@ -396,7 +396,7 @@ test.describe("GUI Essential Tools", () => {
});
test("flip vertical enables submit", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
const submitBtn = page.getByTestId("rotate-submit");
@@ -407,7 +407,7 @@ test.describe("GUI Essential Tools", () => {
});
test("180 degree button sets correct angle", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await page.getByRole("button", { name: "180" }).click();
@@ -417,7 +417,7 @@ test.describe("GUI Essential Tools", () => {
});
test("straighten slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
const slider = page.locator("#rotate-straighten");
@@ -426,7 +426,7 @@ test.describe("GUI Essential Tools", () => {
});
test("processes rotation and shows result", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await page.getByTestId("rotate-right").click();
@@ -447,7 +447,7 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Convert", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await expect(page.getByText("Convert").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
@@ -455,7 +455,7 @@ test.describe("GUI Essential Tools", () => {
test("shows source format and target format selector after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await expect(page.getByText("Source Format")).toBeVisible();
@@ -463,7 +463,7 @@ test.describe("GUI Essential Tools", () => {
});
test("format selector contains all output formats", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
const select = page.locator("#convert-target-format");
@@ -473,7 +473,7 @@ test.describe("GUI Essential Tools", () => {
});
test("quality slider appears for lossy formats", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
// Select JPG (lossy)
@@ -486,7 +486,7 @@ test.describe("GUI Essential Tools", () => {
});
test("quality slider appears for WebP format", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", "webp");
@@ -494,7 +494,7 @@ test.describe("GUI Essential Tools", () => {
});
test("quality slider appears for AVIF format", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", "avif");
@@ -502,14 +502,14 @@ test.describe("GUI Essential Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await expect(page.getByTestId("convert-submit")).toBeVisible();
});
test("quality slider hidden for TIFF lossless format", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", "tiff");
@@ -517,7 +517,7 @@ test.describe("GUI Essential Tools", () => {
});
test("changing format resets quality slider visibility", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
// Start with JPG (lossy, shows quality)
@@ -534,7 +534,7 @@ test.describe("GUI Essential Tools", () => {
});
test("processes conversion and shows download", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", "webp");
@@ -550,13 +550,13 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Compress", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await expect(page.getByText("Compress").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows compression mode toggle after upload", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
await expect(page.getByText("Compression Mode")).toBeVisible();
@@ -565,7 +565,7 @@ test.describe("GUI Essential Tools", () => {
});
test("quality mode shows quality slider", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; switch to Quality mode first
@@ -576,7 +576,7 @@ test.describe("GUI Essential Tools", () => {
});
test("target size mode shows size input", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
await page.getByRole("button", { name: "Target Size" }).click();
@@ -584,7 +584,7 @@ test.describe("GUI Essential Tools", () => {
});
test("quality slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; switch to Quality mode first
@@ -595,7 +595,7 @@ test.describe("GUI Essential Tools", () => {
});
test("target size mode shows size input and unit", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
await page.getByRole("button", { name: "Target Size" }).click();
@@ -603,14 +603,14 @@ test.describe("GUI Essential Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
await expect(page.getByTestId("compress-submit")).toBeVisible();
});
test("switching between Quality and Target Size modes", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; verify its input is visible
@@ -628,7 +628,7 @@ test.describe("GUI Essential Tools", () => {
test("submit disabled without file, enabled with file in quality mode", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
const submitBtn = page.getByTestId("compress-submit");
await expect(submitBtn).toBeDisabled();
@@ -642,7 +642,7 @@ test.describe("GUI Essential Tools", () => {
test("processes compression and shows download with size info", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; switch to Quality mode so submit is enabled
@@ -663,7 +663,7 @@ test.describe("GUI Essential Tools", () => {
test("resize: undo after processing reverts to upload state", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("50");
@@ -682,7 +682,7 @@ test.describe("GUI Essential Tools", () => {
});
test("crop: undo after processing returns to crop canvas", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -706,7 +706,7 @@ test.describe("GUI Essential Tools", () => {
test("rotate: undo after processing returns to rotate controls", async ({
loggedInPage: page,
}) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await page.getByTestId("rotate-right").click();
@@ -728,7 +728,7 @@ test.describe("GUI Essential Tools", () => {
test("convert: undo after processing returns to format selector", async ({
loggedInPage: page,
}) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.selectOption("#convert-target-format", "webp");
@@ -746,7 +746,7 @@ test.describe("GUI Essential Tools", () => {
test("compress: undo after processing returns to quality slider", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; switch to Quality mode so submit is enabled
@@ -765,7 +765,7 @@ test.describe("GUI Essential Tools", () => {
});
test("resize: clear all returns to dropzone", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await expect(page.locator("#resize-width")).toBeVisible();
@@ -778,17 +778,17 @@ test.describe("GUI Essential Tools", () => {
});
test("navigate away from tool resets state", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("50");
// Navigate to a different tool
await page.goto("/crop");
await page.goto("/image/crop");
await expect(page.getByText("Crop").first()).toBeVisible();
// Navigate back -- state should be reset
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.getByText("Upload from computer")).toBeVisible();
});
});
@@ -798,7 +798,7 @@ test.describe("GUI Essential Tools", () => {
// ========================================================================
test.describe("Result Display Modes", () => {
test("resize: shows side-by-side display after processing", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.locator("#resize-width").fill("50");
@@ -814,7 +814,7 @@ test.describe("GUI Essential Tools", () => {
test("compress: shows before-after display with size savings", async ({
loggedInPage: page,
}) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Default mode is Target Size; switch to Quality mode so submit is enabled
@@ -873,7 +873,7 @@ test.describe("GUI Essential Tools", () => {
test("crop canvas renders with ReactCrop component after upload", async ({
loggedInPage: page,
}) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -883,7 +883,7 @@ test.describe("GUI Essential Tools", () => {
});
test("crop handles are visible on the canvas", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -901,7 +901,7 @@ test.describe("GUI Essential Tools", () => {
test("dragging on crop canvas updates numeric position inputs", async ({
loggedInPage: page,
}) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -937,7 +937,7 @@ test.describe("GUI Essential Tools", () => {
test("selecting 1:1 aspect ratio constrains crop box proportions", async ({
loggedInPage: page,
}) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await page.waitForTimeout(1000);
File diff suppressed because it is too large Load Diff
+77 -77
View File
@@ -13,18 +13,18 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("SVG to Raster", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByText("SVG to Raster").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows settings section", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByText("Settings").first()).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
// SVG tool needs an SVG file; just verify the submit testid exists on the page
await expect(page.getByTestId("svg-to-raster-submit")).toBeVisible();
});
@@ -32,14 +32,14 @@ test.describe("GUI Format & Conversion Tools", () => {
test("shows sizing mode buttons (Scale Factor / Custom Size)", async ({
loggedInPage: page,
}) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByRole("button", { name: "Scale Factor" })).toBeVisible();
await expect(page.getByRole("button", { name: "Custom Size" })).toBeVisible();
});
test("shows DPI preset buttons", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByRole("button", { name: "72" })).toBeVisible();
await expect(page.getByRole("button", { name: "96" })).toBeVisible();
@@ -48,7 +48,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows format buttons (png, jpg, webp, avif, etc.)", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByRole("button", { name: /^png$/i })).toBeVisible();
await expect(page.getByRole("button", { name: /^jpg$/i })).toBeVisible();
@@ -56,14 +56,14 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows background mode buttons (Transparent / Color)", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await expect(page.getByRole("button", { name: "Transparent" })).toBeVisible();
await expect(page.getByRole("button", { name: "Color" })).toBeVisible();
});
test("color mode shows color presets when selected", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await page.getByRole("button", { name: "Color" }).click();
// Should show white and black color buttons
@@ -72,7 +72,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("custom size mode shows width and height inputs", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
await page.getByRole("button", { name: "Custom Size" }).click();
await expect(page.locator("#svg-custom-width")).toBeVisible();
@@ -80,7 +80,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("scale factor mode shows scale presets", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
// Scale presets require an SVG file to detect dimensions; upload a test SVG
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -97,7 +97,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/svg-to-raster");
await page.goto("/image/svg-to-raster");
const submitBtn = page.getByTestId("svg-to-raster-submit");
await expect(submitBtn).toBeDisabled();
@@ -109,13 +109,13 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("Vectorize", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await expect(page.getByText("Image to SVG").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows preset buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
// Presets from vectorize-settings.tsx
@@ -126,7 +126,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows color mode toggle after upload", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
// Color mode: B&W / Color from vectorize-settings.tsx
@@ -134,7 +134,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows detail level buttons (low, medium, high)", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: /^low$/i })).toBeVisible();
@@ -143,7 +143,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows smoothing buttons (none, polygon, spline)", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: /^none$/i })).toBeVisible();
@@ -152,14 +152,14 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows invert colors toggle", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await expect(page.getByText("Invert Colors")).toBeVisible();
});
test("switching to color mode shows color precision slider", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
// Logo preset defaults to B&W -- switch to illustration for color mode
@@ -169,7 +169,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("B&W mode shows threshold slider", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
// Logo preset defaults to B&W
@@ -178,21 +178,21 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows custom preset button", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: /^custom$/i })).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await expect(page.getByTestId("vectorize-submit")).toBeVisible();
});
test("processes vectorize and shows download", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await page.getByRole("button", { name: /vectorize/i }).click();
@@ -209,13 +209,13 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("GIF Tools", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await expect(page.getByText("GIF").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows mode selector tabs after upload", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
// Mode tabs from gif-tools-settings.tsx
@@ -224,12 +224,12 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows settings section", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await expect(page.getByText("Settings").first()).toBeVisible();
});
test("shows all six mode tabs after upload", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Resize" }).first()).toBeVisible();
@@ -242,7 +242,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("resize mode shows pixel and percentage tabs", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
// Resize is default mode
@@ -251,7 +251,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("resize pixel mode shows width and height inputs", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await expect(page.locator("#gif-width")).toBeVisible();
@@ -259,7 +259,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("optimize mode shows colors and dither sliders", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await page.getByRole("button", { name: "Optimize" }).first().click();
@@ -269,7 +269,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("rotate mode shows angle buttons and flip controls", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await page.getByRole("button", { name: "Rotate" }).first().click();
@@ -280,7 +280,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows loop control section", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await expect(page.getByText("Loop")).toBeVisible();
@@ -290,7 +290,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("speed mode shows speed factor controls", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
// Speed mode requires an animated GIF (disabled for static images)
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -306,7 +306,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("extract mode shows extract controls", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
// Extract mode requires an animated GIF (disabled for static images)
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -324,7 +324,7 @@ test.describe("GUI Format & Conversion Tools", () => {
test("custom loop count input appears when Custom is selected", async ({
loggedInPage: page,
}) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await page.getByRole("button", { name: "Custom" }).click();
@@ -333,14 +333,14 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
await uploadTestImage(page);
await expect(page.getByTestId("gif-tools-submit")).toBeVisible();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/gif-tools");
await page.goto("/image/gif-tools");
const submitBtn = page.getByTestId("gif-tools-submit");
await expect(submitBtn).toBeDisabled();
@@ -355,13 +355,13 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("Image to PDF", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await expect(page.getByText("Image to PDF").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows page size and orientation controls", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await expect(page.getByText("Page Size")).toBeVisible();
await expect(page.getByText("Orientation")).toBeVisible();
@@ -370,13 +370,13 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows submit button with page count", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await expect(page.getByTestId("image-to-pdf-submit")).toBeVisible();
});
test("shows page size dropdown with options", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
const select = page.locator("#image-to-pdf-page-size");
await expect(select).toBeVisible();
@@ -385,14 +385,14 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("changing page size selects new value", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await page.selectOption("#image-to-pdf-page-size", "Letter");
await expect(page.locator("#image-to-pdf-page-size")).toHaveValue("Letter");
});
test("shows margin slider", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
const slider = page.locator("#image-to-pdf-margin");
await expect(slider).toBeVisible();
@@ -400,7 +400,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows target file size input", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await expect(page.getByTestId("image-to-pdf-target-size-value")).toBeVisible();
await expect(page.getByTestId("image-to-pdf-target-size-unit")).toBeVisible();
@@ -409,14 +409,14 @@ test.describe("GUI Format & Conversion Tools", () => {
test("orientation buttons toggle between portrait and landscape", async ({
loggedInPage: page,
}) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await page.getByRole("button", { name: "Landscape" }).click();
await page.getByRole("button", { name: "Portrait" }).click();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
const submitBtn = page.getByTestId("image-to-pdf-submit");
await expect(submitBtn).toBeDisabled();
@@ -426,7 +426,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("processes image to PDF and shows download", async ({ loggedInPage: page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await uploadTestImage(page);
await page.getByTestId("image-to-pdf-submit").click();
@@ -441,7 +441,7 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("PDF to Image", () => {
test("renders tool page without standard dropzone", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByText("PDF to Image").first()).toBeVisible();
// PDF to Image uses no-dropzone display mode with custom file input
@@ -449,27 +449,27 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows format options", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
// Format options from pdf-to-image-settings.tsx
await expect(page.getByText(/format/i).first()).toBeVisible();
});
test("shows DPI presets", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
// DPI buttons from pdf-to-image-settings.tsx
await expect(page.getByText(/dpi|resolution/i).first()).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByTestId("pdf-to-image-submit")).toBeVisible();
});
test("shows all format buttons", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByText("Output Format")).toBeVisible();
await expect(page.getByRole("button", { name: "PNG" }).first()).toBeVisible();
@@ -478,7 +478,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows DPI preset buttons", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByText("Resolution (DPI)")).toBeVisible();
await expect(page.getByRole("button", { name: "72" }).first()).toBeVisible();
@@ -488,7 +488,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows color mode buttons", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByText("Color Mode")).toBeVisible();
await expect(page.getByRole("button", { name: "Color" }).first()).toBeVisible();
@@ -497,25 +497,25 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows pages input field", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.locator("#pdf-pages")).toBeVisible();
});
test("shows PDF upload area", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByText("Drop a PDF here or click to select")).toBeVisible();
});
test("submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByTestId("pdf-to-image-submit")).toBeDisabled();
});
test("shows Custom DPI button", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
await expect(page.getByRole("button", { name: "Custom" }).first()).toBeVisible();
});
@@ -526,20 +526,20 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("Favicon Generator", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await expect(page.getByText("Favicon").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows generate button after upload", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: /generate/i }).first()).toBeVisible();
});
test("shows generated sizes list", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await expect(page.getByText("Generated Sizes")).toBeVisible();
await expect(page.getByText("favicon-16x16.png")).toBeVisible();
@@ -550,21 +550,21 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows manifest and HTML snippet mention", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await expect(page.getByText("manifest.json")).toBeVisible();
await expect(page.getByText("HTML snippet")).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await uploadTestImage(page);
await expect(page.getByTestId("favicon-submit")).toBeVisible();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
const submitBtn = page.getByTestId("favicon-submit");
await expect(submitBtn).toBeDisabled();
@@ -574,7 +574,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("processes favicon generation and shows download", async ({ loggedInPage: page }) => {
await page.goto("/favicon");
await page.goto("/image/favicon");
await uploadTestImage(page);
await page.getByTestId("favicon-submit").click();
@@ -591,13 +591,13 @@ test.describe("GUI Format & Conversion Tools", () => {
// ========================================================================
test.describe("Optimize for Web", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await expect(page.getByText("Optimize for Web").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// Format buttons from optimize-for-web-settings.tsx
@@ -605,21 +605,21 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows quality slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
await expect(page.getByText(/quality/i).first()).toBeVisible();
});
test("shows strip metadata checkbox after upload", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
await expect(page.getByText(/strip metadata|remove metadata/i).first()).toBeVisible();
});
test("shows all five format buttons", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -632,7 +632,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("quality slider hidden for PNG format", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -642,7 +642,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("quality slider visible for WebP format", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -652,7 +652,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("shows collapsible Max Dimensions section", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
await expect(page.getByText("Max Dimensions")).toBeVisible();
@@ -664,7 +664,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("strip metadata toggle is interactive", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
const toggle = page.locator("#strip-meta");
@@ -677,7 +677,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("submit button is enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// The optimize-for-web submit is a form submit button (no data-testid)
@@ -687,7 +687,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
// The optimize-for-web submit is a form submit button (no data-testid)
const submitBtn = page.locator("button[type='submit']");
@@ -695,7 +695,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("quality slider value changes for JPEG format", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// Scope to the settings panel to avoid matching the file list item button
@@ -707,7 +707,7 @@ test.describe("GUI Format & Conversion Tools", () => {
});
test("processes optimization and shows download", async ({ loggedInPage: page }) => {
await page.goto("/optimize-for-web");
await page.goto("/image/optimize-for-web");
await uploadTestImage(page);
// The optimize-for-web submit is a form submit button (no data-testid)
+36 -36
View File
@@ -11,7 +11,7 @@ test.describe("GUI Layout Tools", () => {
// ========================================================================
test.describe("Collage", () => {
test("renders tool page without standard dropzone", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
await expect(page.getByText("Collage").first()).toBeVisible();
// Collage uses custom upload UI, not standard dropzone
@@ -19,7 +19,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows aspect ratio options in Canvas section", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
// Canvas section is collapsed by default -- expand it
await page.getByText("Canvas").click();
@@ -31,7 +31,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows output format selector in Output section", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
// Output section is collapsed by default -- expand it
await page.getByText("Output").click();
@@ -42,34 +42,34 @@ test.describe("GUI Layout Tools", () => {
});
test("shows background color in Spacing section", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
// Spacing & Style section is open by default
await expect(page.getByText(/background/i).first()).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
await expect(page.getByTestId("collage-submit")).toBeVisible();
});
test("shows gap/spacing slider in Spacing section", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
// Spacing & Style section should show gap controls
await expect(page.getByText(/gap|spacing/i).first()).toBeVisible();
});
test("submit button is disabled without images", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
const submitBtn = page.getByTestId("collage-submit");
await expect(submitBtn).toBeDisabled();
});
test("shows quality slider in Output section for JPEG", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
await page.getByText("Output").click();
await page.getByRole("button", { name: "JPEG" }).first().click();
@@ -83,13 +83,13 @@ test.describe("GUI Layout Tools", () => {
// ========================================================================
test.describe("Stitch", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await expect(page.getByText("Stitch").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows direction options after upload", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
// Direction buttons: horizontal, vertical, grid
@@ -99,21 +99,21 @@ test.describe("GUI Layout Tools", () => {
});
test("shows resize mode options after upload", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
await expect(page.getByText(/resize mode|fit|original/i).first()).toBeVisible();
});
test("shows alignment options after upload", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
await expect(page.getByText(/alignment|align/i).first()).toBeVisible();
});
test("submit button uses data-testid and has correct label", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
const submitBtn = page.getByTestId("stitch-submit");
@@ -121,7 +121,7 @@ test.describe("GUI Layout Tools", () => {
});
test("submit disabled without file, enabled with 2+ files", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
const submitBtn = page.getByTestId("stitch-submit");
await expect(submitBtn).toBeDisabled();
@@ -141,7 +141,7 @@ test.describe("GUI Layout Tools", () => {
});
test("direction buttons switch active state", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
// Click vertical
@@ -159,7 +159,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows gap slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/stitch");
await page.goto("/image/stitch");
await uploadTestImage(page);
await expect(page.getByText(/gap/i).first()).toBeVisible();
@@ -171,13 +171,13 @@ test.describe("GUI Layout Tools", () => {
// ========================================================================
test.describe("Split", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await expect(page.getByText("Image Splitting").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows mode selector (Grid / Tile Size) after upload", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Grid" }).first()).toBeVisible();
@@ -185,7 +185,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows grid presets after upload", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
// Grid presets from split-settings.tsx
@@ -194,7 +194,7 @@ test.describe("GUI Layout Tools", () => {
});
test("tile size mode shows width and height inputs", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
await page.getByRole("button", { name: "Tile Size" }).first().click();
@@ -203,7 +203,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows output format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
// Output format options
@@ -211,7 +211,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows 3x3 and 4x4 grid presets", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "3x3" }).first()).toBeVisible();
@@ -219,7 +219,7 @@ test.describe("GUI Layout Tools", () => {
});
test("switching to tile size mode and back to grid works", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
await page.getByRole("button", { name: "Tile Size" }).first().click();
@@ -229,7 +229,7 @@ test.describe("GUI Layout Tools", () => {
});
test("processes split and shows download", async ({ loggedInPage: page }) => {
await page.goto("/split");
await page.goto("/image/split");
await uploadTestImage(page);
await page.waitForTimeout(1000);
@@ -259,13 +259,13 @@ test.describe("GUI Layout Tools", () => {
// ========================================================================
test.describe("Beautify", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Beautify").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows Quick Presets section with preset buttons", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Quick Presets")).toBeVisible();
await expect(page.getByText("Purple Haze")).toBeVisible();
@@ -277,7 +277,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows Background section with tabs", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Background").first()).toBeVisible();
await expect(page.getByRole("button", { name: "Gradient" })).toBeVisible();
@@ -287,7 +287,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows Device Frame section with frame types", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Device Frame")).toBeVisible();
await expect(page.getByRole("button", { name: "macOS" })).toBeVisible();
@@ -297,7 +297,7 @@ test.describe("GUI Layout Tools", () => {
});
test("frame type shows Light/Dark theme toggle", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
// macOS is default frame -- should show theme toggle
await expect(page.getByRole("button", { name: "Light" }).first()).toBeVisible();
@@ -307,7 +307,7 @@ test.describe("GUI Layout Tools", () => {
test("shows Spacing section with padding and border radius sliders", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Spacing")).toBeVisible();
await expect(page.locator("#beautify-padding")).toBeVisible();
@@ -315,7 +315,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows Shadow section with preset chips", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Shadow").first()).toBeVisible();
await expect(page.getByRole("button", { name: "Subtle" })).toBeVisible();
@@ -324,7 +324,7 @@ test.describe("GUI Layout Tools", () => {
});
test("custom shadow shows blur/offset/color controls", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await page.getByRole("button", { name: "Custom" }).first().click();
await expect(page.locator("#beautify-shadow-blur")).toBeVisible();
@@ -337,7 +337,7 @@ test.describe("GUI Layout Tools", () => {
test("shows collapsible Export Size section with social presets", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Export Size")).toBeVisible();
await page.getByText("Export Size").click();
@@ -347,7 +347,7 @@ test.describe("GUI Layout Tools", () => {
});
test("shows collapsible Watermark section", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await expect(page.getByText("Watermark").first()).toBeVisible();
await page.getByText("Watermark").first().click();
@@ -359,7 +359,7 @@ test.describe("GUI Layout Tools", () => {
test("submit button disabled without file, enabled with file", async ({
loggedInPage: page,
}) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
const submitBtn = page.getByTestId("beautify-submit");
await expect(submitBtn).toBeDisabled();
@@ -369,7 +369,7 @@ test.describe("GUI Layout Tools", () => {
});
test("processes beautify and shows download", async ({ loggedInPage: page }) => {
await page.goto("/beautify");
await page.goto("/image/beautify");
await uploadTestImage(page);
await page.getByTestId("beautify-submit").click();
+27 -27
View File
@@ -11,13 +11,13 @@ test.describe("GUI Metadata Tools", () => {
// ========================================================================
test.describe("Strip Metadata", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await expect(page.getByText("Remove Metadata").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows strip options after upload", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
// Remove All checkbox is checked by default
@@ -32,7 +32,7 @@ test.describe("GUI Metadata Tools", () => {
test("individual strip options disabled when Remove All is checked", async ({
loggedInPage: page,
}) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
// With Remove All checked, individual checkboxes should be disabled
@@ -44,7 +44,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("unchecking Remove All enables individual options", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
// Uncheck Remove All
@@ -63,7 +63,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("auto-inspects metadata on upload", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
// Should show "Current Metadata" heading or "Reading metadata..." or "No metadata found"
@@ -77,7 +77,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("processes strip and shows download", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
await page.getByTestId("strip-metadata-submit").click();
@@ -92,13 +92,13 @@ test.describe("GUI Metadata Tools", () => {
// ========================================================================
test.describe("Edit Metadata", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await expect(page.getByText("Edit Metadata").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows form fields after upload and inspection", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
// Wait for inspection to complete
@@ -112,7 +112,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("shows collapsible sections", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -123,7 +123,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("date mode toggle between Edit and Shift", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -134,7 +134,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("GPS section shows clear GPS checkbox", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -146,7 +146,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("edits artist field and processes", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -158,7 +158,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("shows changes summary when fields are modified", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -167,7 +167,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("shows copyright and description fields", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -176,7 +176,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -189,13 +189,13 @@ test.describe("GUI Metadata Tools", () => {
// ========================================================================
test.describe("Image Info", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await expect(page.getByText("Image Info").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows Read Info button after upload", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await expect(page.getByTestId("info-submit")).toBeVisible();
@@ -203,7 +203,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("displays image metadata after Read Info", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await page.getByTestId("info-submit").click();
@@ -218,7 +218,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("shows channel stats histogram after Read Info", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await page.getByTestId("info-submit").click();
@@ -228,7 +228,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("no download link for info tool (read-only)", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await page.getByTestId("info-submit").click();
@@ -239,7 +239,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
const submitBtn = page.getByTestId("info-submit");
await expect(submitBtn).toBeDisabled();
@@ -256,7 +256,7 @@ test.describe("GUI Metadata Tools", () => {
test("strip-metadata: undo after processing returns to settings", async ({
loggedInPage: page,
}) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
await page.getByTestId("strip-metadata-submit").click();
@@ -273,7 +273,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("edit-metadata: undo after processing returns to form", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
await page.waitForSelector('[id="em-artist"]', { timeout: 10_000 });
@@ -290,7 +290,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("strip-metadata: clear all returns to dropzone", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
await expect(page.getByText("Remove All Metadata")).toBeVisible();
@@ -301,7 +301,7 @@ test.describe("GUI Metadata Tools", () => {
});
test("navigate away from info tool resets state", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await page.getByTestId("info-submit").click();
@@ -310,8 +310,8 @@ test.describe("GUI Metadata Tools", () => {
await expect(page.getByText("Dimensions").first()).toBeVisible({ timeout: 15_000 });
// Navigate away and back
await page.goto("/resize");
await page.goto("/info");
await page.goto("/image/resize");
await page.goto("/image/info");
// Should be back at dropzone
await expect(page.getByText("Upload from computer")).toBeVisible();
+69 -69
View File
@@ -14,13 +14,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
// ========================================================================
test.describe("Watermark Text", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await expect(page.getByText("Text Watermark").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows watermark text input and settings after upload", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-text")).toBeVisible();
@@ -29,14 +29,14 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("font size slider visible", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-font-size")).toBeVisible();
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
const submitBtn = page.getByTestId("watermark-text-submit");
await expect(submitBtn).toBeDisabled();
@@ -46,21 +46,21 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows color picker for watermark text", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-color")).toBeVisible();
});
test("shows opacity slider", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-opacity")).toBeVisible();
});
test("shows position dropdown with all options", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
const select = page.locator("#watermark-text-position");
@@ -70,14 +70,14 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows rotation slider", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-rotation")).toBeVisible();
});
test("opacity slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
const slider = page.locator("#watermark-text-opacity");
@@ -86,7 +86,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("font size slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
const slider = page.locator("#watermark-text-font-size");
@@ -95,7 +95,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("changing text input updates value", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await page.locator("#watermark-text-text").fill("My Custom Text");
@@ -103,7 +103,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes watermark and shows download", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await page.locator("#watermark-text-text").fill("Test Watermark");
@@ -121,13 +121,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
// ========================================================================
test.describe("Watermark Image", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await expect(page.getByText("Image Watermark").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows position and opacity controls after upload", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
// Position selector should be visible
@@ -137,7 +137,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows watermark upload area after main image upload", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
// Should see a prompt to upload the watermark/logo image
@@ -145,7 +145,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows position dropdown with five options", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
const select = page.locator("#watermark-image-position");
@@ -155,21 +155,21 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows opacity slider with percentage", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
await expect(page.locator("#watermark-image-opacity")).toBeVisible();
});
test("shows scale slider with percentage", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
await expect(page.locator("#watermark-image-scale")).toBeVisible();
});
test("submit disabled without watermark file", async ({ loggedInPage: page }) => {
await page.goto("/watermark-image");
await page.goto("/image/watermark-image");
await uploadTestImage(page);
const submitBtn = page.getByTestId("watermark-image-submit");
@@ -182,13 +182,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
// ========================================================================
test.describe("Text Overlay", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await expect(page.getByText("Text Overlay").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows text input and font size slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await expect(page.locator("#text-overlay-text")).toBeVisible();
@@ -197,7 +197,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
const submitBtn = page.getByTestId("text-overlay-submit");
await expect(submitBtn).toBeDisabled();
@@ -207,14 +207,14 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows text color picker", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await expect(page.locator("#text-overlay-color")).toBeVisible();
});
test("shows position dropdown with three options", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
const select = page.locator("#text-overlay-position");
@@ -224,14 +224,14 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows drop shadow checkbox", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await expect(page.getByText("Drop Shadow")).toBeVisible();
});
test("background box checkbox reveals box color picker", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await expect(page.getByText("Background Box")).toBeVisible();
@@ -251,7 +251,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("font size slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
const slider = page.locator("#text-overlay-font-size");
@@ -260,7 +260,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("changing text input updates value", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await page.locator("#text-overlay-text").fill("Custom Overlay");
@@ -268,7 +268,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes text overlay and shows download", async ({ loggedInPage: page }) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await page.getByTestId("text-overlay-submit").click();
@@ -302,13 +302,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
}
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await expect(page.getByText("Image Composition").first()).toBeVisible();
await expect(page.locator("section[aria-label='File drop zone']")).toBeVisible();
});
test("shows overlay upload and position controls", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await expect(page.getByText("X Position")).toBeVisible();
await expect(page.getByText("Y Position")).toBeVisible();
@@ -318,27 +318,27 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows overlay image upload button", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await expect(page.getByText("Overlay Image").first()).toBeVisible();
await expect(page.getByText("Choose overlay image")).toBeVisible();
});
test("shows X and Y position number inputs", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await expect(page.locator("#compose-x-position")).toBeVisible();
await expect(page.locator("#compose-y-position")).toBeVisible();
});
test("shows opacity slider", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await expect(page.locator("#compose-opacity")).toBeVisible();
});
test("blend mode dropdown has all options", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
const select = page.locator("#compose-blend-mode");
await expect(select).toBeVisible();
@@ -347,7 +347,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("submit disabled without overlay file", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
const submitBtn = page.getByTestId("compose-submit");
@@ -355,7 +355,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("submit enabled after uploading both base and overlay", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
await uploadOverlayImage(page);
@@ -363,7 +363,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes composition and shows download", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
await uploadOverlayImage(page);
@@ -374,7 +374,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes with custom position and opacity", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
await uploadOverlayImage(page);
@@ -389,7 +389,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes with multiply blend mode", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
await uploadOverlayImage(page);
@@ -402,14 +402,14 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("overlay filename shown after selection", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadOverlayImage(page);
await expect(page.getByText("test-image.png")).toBeVisible();
});
test("shows size info after processing", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
await uploadOverlayImage(page);
@@ -422,7 +422,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes webp overlay on png base", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
const webpPath = path.join(
@@ -442,7 +442,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows error for corrupt overlay file", async ({ loggedInPage: page }) => {
await page.goto("/compose");
await page.goto("/image/compose");
await uploadBaseImage(page);
const tmpDir = path.join(process.cwd(), "test-results");
@@ -463,13 +463,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
// ========================================================================
test.describe("Border", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await expect(page.getByText("Border").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows border preset buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
// Presets from border-settings.tsx
@@ -480,56 +480,56 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows border width and color controls after upload", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.getByText(/border width|width/i).first()).toBeVisible();
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.getByTestId("border-submit")).toBeVisible();
});
test("shows border width slider", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#border-width")).toBeVisible();
});
test("shows border color swatches", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#border-color")).toBeVisible();
});
test("shows padding slider", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#border-padding")).toBeVisible();
});
test("shows padding color swatches", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#padding-color")).toBeVisible();
});
test("shows corner radius slider", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#border-corner-radius")).toBeVisible();
});
test("shadow toggle reveals shadow controls", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
// Shadow toggle switch
@@ -551,7 +551,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("shows all preset buttons", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.getByText("Polaroid").first()).toBeVisible();
@@ -561,7 +561,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("border width slider is interactive", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
const slider = page.locator("#border-width");
@@ -570,7 +570,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("clicking a preset updates border settings", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
// Click Polaroid preset
@@ -580,7 +580,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("submit disabled without file, enabled with file", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
const submitBtn = page.getByTestId("border-submit");
await expect(submitBtn).toBeDisabled();
@@ -590,7 +590,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("processes border and shows download", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await page.getByTestId("border-submit").click();
@@ -607,7 +607,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
test("watermark-text: undo after processing returns to text input", async ({
loggedInPage: page,
}) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await page.locator("#watermark-text-text").fill("Undo Test");
@@ -626,7 +626,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
test("text-overlay: undo after processing returns to settings", async ({
loggedInPage: page,
}) => {
await page.goto("/text-overlay");
await page.goto("/image/text-overlay");
await uploadTestImage(page);
await page.getByTestId("text-overlay-submit").click();
@@ -644,7 +644,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
test("compose: undo after processing returns to position controls", async ({
loggedInPage: page,
}) => {
await page.goto("/compose");
await page.goto("/image/compose");
// Use compose-specific upload helpers
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -671,7 +671,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
test("border: undo after processing returns to preset buttons", async ({
loggedInPage: page,
}) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await page.getByTestId("border-submit").click();
@@ -687,7 +687,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("watermark-text: clear all returns to dropzone", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
await expect(page.locator("#watermark-text-text")).toBeVisible();
@@ -698,13 +698,13 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("border: navigate away resets state", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
await expect(page.locator("#border-width")).toBeVisible();
await page.goto("/watermark-text");
await page.goto("/border");
await page.goto("/image/watermark-text");
await page.goto("/image/border");
await expect(page.getByText("Upload from computer")).toBeVisible();
});
@@ -715,7 +715,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
// ========================================================================
test.describe("Border Live Preview", () => {
test("selecting a preset updates the live preview styling", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
const previewImg = page.locator("img").first();
@@ -734,7 +734,7 @@ test.describe("GUI Watermark & Overlay Tools", () => {
});
test("changing border width updates preview in real-time", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
const previewImg = page.locator("img").first();
+45 -45
View File
@@ -21,13 +21,13 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("Image Compare", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/compare");
await page.goto("/image/compare");
await expect(page.getByText("Image Compare").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows second image upload prompt after first upload", async ({ loggedInPage: page }) => {
await page.goto("/compare");
await page.goto("/image/compare");
await uploadTestImage(page);
// Compare tool requires a second image
@@ -35,14 +35,14 @@ test.describe("GUI Utility Tools", () => {
});
test("shows second image upload button with correct label", async ({ loggedInPage: page }) => {
await page.goto("/compare");
await page.goto("/image/compare");
await expect(page.getByText("Second Image").first()).toBeVisible();
await expect(page.getByText("Choose second image")).toBeVisible();
});
test("submit disabled without both images", async ({ loggedInPage: page }) => {
await page.goto("/compare");
await page.goto("/image/compare");
const submitBtn = page.getByTestId("compare-submit");
await expect(submitBtn).toBeDisabled();
@@ -53,7 +53,7 @@ test.describe("GUI Utility Tools", () => {
});
test("submit button text says Compare", async ({ loggedInPage: page }) => {
await page.goto("/compare");
await page.goto("/image/compare");
await expect(page.getByTestId("compare-submit")).toHaveText(/Compare/);
});
@@ -64,13 +64,13 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("Find Duplicates", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/find-duplicates");
await page.goto("/image/find-duplicates");
await expect(page.getByText("Find Duplicates").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows preset sensitivity buttons after upload", async ({ loggedInPage: page }) => {
await page.goto("/find-duplicates");
await page.goto("/image/find-duplicates");
await uploadTestImage(page);
// Preset buttons from find-duplicates-settings.tsx
@@ -80,14 +80,14 @@ test.describe("GUI Utility Tools", () => {
});
test("shows sensitivity threshold slider after upload", async ({ loggedInPage: page }) => {
await page.goto("/find-duplicates");
await page.goto("/image/find-duplicates");
await uploadTestImage(page);
await expect(page.locator("input[type='range']").first()).toBeVisible();
});
test("preset click updates threshold slider", async ({ loggedInPage: page }) => {
await page.goto("/find-duplicates");
await page.goto("/image/find-duplicates");
await uploadTestImage(page);
// Click exact preset
@@ -97,7 +97,7 @@ test.describe("GUI Utility Tools", () => {
});
test("scan button requires at least 2 files", async ({ loggedInPage: page }) => {
await page.goto("/find-duplicates");
await page.goto("/image/find-duplicates");
await uploadTestImage(page);
// With only one file, scan should be disabled
@@ -111,13 +111,13 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("Image to Base64", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await expect(page.getByText("Image to Base64").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows output format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
// Output format dropdown (Keep Original, JPEG, PNG, WebP, AVIF)
@@ -125,7 +125,7 @@ test.describe("GUI Utility Tools", () => {
});
test("shows all output format buttons", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
await expect(page.getByRole("button", { name: "Keep Original", exact: true })).toBeVisible();
@@ -136,7 +136,7 @@ test.describe("GUI Utility Tools", () => {
});
test("quality slider appears for lossy formats", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
// Keep Original is default -- no quality slider
@@ -148,7 +148,7 @@ test.describe("GUI Utility Tools", () => {
});
test("shows max width and max height inputs", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
await expect(page.locator("#b64-max-width")).toBeVisible();
@@ -156,7 +156,7 @@ test.describe("GUI Utility Tools", () => {
});
test("submit button uses data-testid", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
await expect(page.getByTestId("base64-submit")).toBeVisible();
@@ -164,7 +164,7 @@ test.describe("GUI Utility Tools", () => {
});
test("quality slider hidden for PNG format", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
await page.getByRole("button", { name: "PNG", exact: true }).click();
@@ -172,7 +172,7 @@ test.describe("GUI Utility Tools", () => {
});
test("switching format to AVIF shows quality slider", async ({ loggedInPage: page }) => {
await page.goto("/image-to-base64");
await page.goto("/image/image-to-base64");
await uploadTestImage(page);
await page.getByRole("button", { name: "AVIF", exact: true }).click();
@@ -185,13 +185,13 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("Barcode Reader", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/barcode-read");
await page.goto("/image/barcode-read");
await expect(page.getByText("Barcode").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows scan button after upload", async ({ loggedInPage: page }) => {
await page.goto("/barcode-read");
await page.goto("/image/barcode-read");
const fileChooserPromise = page.waitForEvent("filechooser");
await page.locator("[class*='border-dashed']").first().click();
@@ -205,7 +205,7 @@ test.describe("GUI Utility Tools", () => {
test("processes scan and shows result or no-barcode message", async ({
loggedInPage: page,
}) => {
await page.goto("/barcode-read");
await page.goto("/image/barcode-read");
await uploadTestImage(page);
await page.getByTestId("barcode-read-submit").click();
@@ -226,7 +226,7 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("QR Code Generator", () => {
test("renders tool page without dropzone", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await expect(page.getByText("QR Code").first()).toBeVisible();
// QR generate has no file upload dropzone
@@ -234,7 +234,7 @@ test.describe("GUI Utility Tools", () => {
});
test("shows content type tabs", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
// Content type tabs from qr-generate-settings.tsx
await expect(page.getByText("URL").first()).toBeVisible();
@@ -244,7 +244,7 @@ test.describe("GUI Utility Tools", () => {
});
test("URL input generates live QR preview", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByTestId("qr-input-url").fill("https://example.com");
// Canvas or SVG should render in the preview area
@@ -252,7 +252,7 @@ test.describe("GUI Utility Tools", () => {
});
test("download button enabled after URL input", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByTestId("qr-input-url").fill("https://example.com");
const downloadBtn = page.getByTestId("qr-generate-download");
@@ -260,7 +260,7 @@ test.describe("GUI Utility Tools", () => {
});
test("dot style options visible", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
// Dot type style buttons from qr-generate-settings.tsx
await expect(page.getByRole("button", { name: "Square" }).first()).toBeVisible();
@@ -269,14 +269,14 @@ test.describe("GUI Utility Tools", () => {
});
test("download format options visible", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await expect(page.getByText("PNG").first()).toBeVisible();
await expect(page.getByText("SVG").first()).toBeVisible();
});
test("WiFi tab shows network inputs", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("WiFi").first().click();
// WiFi tab should show SSID and password inputs
@@ -284,7 +284,7 @@ test.describe("GUI Utility Tools", () => {
});
test("vCard tab shows contact fields", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("vCard").first().click();
// vCard tab should show name input
@@ -292,7 +292,7 @@ test.describe("GUI Utility Tools", () => {
});
test("Text tab shows text input", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("Text").first().click();
// Text tab should have a textarea or input
@@ -300,7 +300,7 @@ test.describe("GUI Utility Tools", () => {
});
test("shows error correction dropdown with four levels", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
const select = page.locator("#qr-error-correction");
await expect(select).toBeVisible();
@@ -309,25 +309,25 @@ test.describe("GUI Utility Tools", () => {
});
test("shows size slider", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await expect(page.locator("#qr-size")).toBeVisible();
});
test("shows corner square style buttons", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await expect(page.getByText("Corner Square")).toBeVisible();
});
test("shows corner dot style buttons", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await expect(page.getByText("Corner Dot")).toBeVisible();
});
test("Email tab shows to/subject/body fields", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("Email").first().click();
await expect(page.locator("#qr-email-to")).toBeVisible();
@@ -335,14 +335,14 @@ test.describe("GUI Utility Tools", () => {
});
test("Phone tab shows phone input", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("Phone").first().click();
await expect(page.locator("#qr-phone")).toBeVisible();
});
test("SMS tab shows phone and message inputs", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.getByText("SMS").first().click();
await expect(page.locator("#qr-sms-phone")).toBeVisible();
@@ -354,13 +354,13 @@ test.describe("GUI Utility Tools", () => {
// ========================================================================
test.describe("Bulk Rename", () => {
test("renders tool page with dropzone", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await expect(page.getByText("Bulk Rename").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("shows pattern input with default value after upload", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
await expect(page.locator("#bulk-rename-pattern")).toBeVisible();
@@ -368,7 +368,7 @@ test.describe("GUI Utility Tools", () => {
});
test("shows pattern variables help text", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
await expect(page.getByText("{{index}}")).toBeVisible();
@@ -377,21 +377,21 @@ test.describe("GUI Utility Tools", () => {
});
test("shows start index input", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
await expect(page.locator("#bulk-rename-start-index")).toBeVisible();
});
test("shows preview of renamed files after upload", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
await expect(page.getByText("Preview")).toBeVisible();
});
test("submit button uses data-testid and shows file count", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
const submitBtn = page.getByTestId("bulk-rename-submit");
@@ -400,7 +400,7 @@ test.describe("GUI Utility Tools", () => {
});
test("changing pattern updates preview", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
await page.locator("#bulk-rename-pattern").fill("photo-{{index}}");
@@ -410,7 +410,7 @@ test.describe("GUI Utility Tools", () => {
});
test("start index input accepts values", async ({ loggedInPage: page }) => {
await page.goto("/bulk-rename");
await page.goto("/image/bulk-rename");
await uploadTestImage(page);
const startIndex = page.locator("#bulk-rename-start-index");
+12 -36
View File
@@ -234,7 +234,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - resize (empty, no file) ----
test("resize tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -243,7 +243,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - resize (file uploaded, settings visible) ----
test("resize tool with file - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.waitForTimeout(500);
@@ -255,7 +255,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - compress (before-after result) ----
test("compress tool before-after result - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
// Upload image and wait for auto-processing
@@ -272,7 +272,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - crop (interactive canvas) ----
test("crop tool interactive canvas - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await page.waitForLoadState("networkidle");
// Upload image to get the interactive crop canvas
@@ -289,7 +289,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - qr-generate (no-dropzone, QR preview) ----
test("qr-generate tool with preview - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -308,7 +308,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - collage (template selection) ----
test("collage tool template selection - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/collage");
await page.goto("/image/collage");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -316,30 +316,6 @@ test.describe("Visual Desktop (1280x720)", () => {
await takeThemedScreenshots(page, "tool-collage-templates");
});
// ---- Analytics consent page ----
test.describe("Analytics consent page", () => {
test.use({ storageState: { cookies: [], origins: [] } });
test("analytics consent page - light and dark", async ({ page }) => {
await page.goto("/analytics-consent");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
// Light screenshot
await expect(page).toHaveScreenshot("desktop-analytics-consent-light.png", {
fullPage: false,
});
// Toggle to dark
await page.keyboard.press(`${MOD}+Shift+d`);
await page.waitForTimeout(300);
await expect(page).toHaveScreenshot("desktop-analytics-consent-dark.png", {
fullPage: false,
});
});
});
// ---- Change password page ----
test("change password page - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/change-password");
@@ -393,7 +369,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - convert (empty state) ----
test("convert tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -402,7 +378,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - convert (file uploaded, format selection visible) ----
test("convert tool with file - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await page.waitForTimeout(500);
@@ -413,7 +389,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - watermark-text (before-after mode) ----
test("watermark-text tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -422,7 +398,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - border (live-preview mode) ----
test("border tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -473,7 +449,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - strip-metadata (no-comparison mode) ----
test("strip-metadata tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -482,7 +458,7 @@ test.describe("Visual Desktop (1280x720)", () => {
// ---- Tool page - info (before-after mode) ----
test("info tool empty - light and dark", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
+7 -7
View File
@@ -2,25 +2,25 @@ import { expect, test } from "@playwright/test";
test.describe("HTML to Image", () => {
test("navigates to the tool page", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
await expect(page.locator("input[type='url']")).toBeVisible();
});
test("shows capture button disabled when URL is empty", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
const button = page.locator("button[type='submit']");
await expect(button).toBeDisabled();
});
test("enables capture button when URL is entered", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
await page.locator("input[type='url']").fill("https://snapotter.com");
const button = page.locator("button[type='submit']");
await expect(button).toBeEnabled();
});
test("captures a webpage and shows the result", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
await page.locator("input[type='url']").fill("https://snapotter.com");
await page.locator("button[type='submit']").click();
@@ -29,7 +29,7 @@ test.describe("HTML to Image", () => {
});
test("shows download button after capture", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
await page.locator("input[type='url']").fill("https://snapotter.com");
await page.locator("button[type='submit']").click();
@@ -38,14 +38,14 @@ test.describe("HTML to Image", () => {
});
test("device preset selector works", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
const preset = page.locator("select").nth(1);
await preset.selectOption("mobile");
await expect(preset).toHaveValue("mobile");
});
test("shows viewport fields when custom preset selected", async ({ page }) => {
await page.goto("/html-to-image");
await page.goto("/image/html-to-image");
const preset = page.locator("select").nth(1);
await preset.selectOption("custom");
+1 -1
View File
@@ -12,7 +12,7 @@ async function uploadViaButton(page: import("@playwright/test").Page) {
test.describe("Image to PDF - Target File Size", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/image-to-pdf");
await page.goto("/image/image-to-pdf");
await page.waitForLoadState("networkidle");
});
+2 -2
View File
@@ -7,7 +7,7 @@ test.describe("Media-player display mode (mute-video)", () => {
test("uploads a video, mutes it, and shows the media player with processed result", async ({
loggedInPage: page,
}) => {
await page.goto("/mute-video");
await page.goto("/video/mute-video");
// Upload tiny.mp4 via the file chooser (dropzone click)
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -42,7 +42,7 @@ test.describe("Media-player display mode (mute-video)", () => {
});
test("media player video element has controls attribute", async ({ loggedInPage: page }) => {
await page.goto("/mute-video");
await page.goto("/video/mute-video");
// Upload tiny.mp4
const fileChooserPromise = page.waitForEvent("filechooser");
+1 -1
View File
@@ -26,7 +26,7 @@ async function removeNoiseAndWait(page: import("@playwright/test").Page) {
test.describe("Noise Removal tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/noise-removal");
await page.goto("/image/noise-removal");
try {
await page.getByTestId("noise-removal-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+1 -1
View File
@@ -18,7 +18,7 @@ async function submitOcr(page: import("@playwright/test").Page) {
test.describe("OCR / Text Extraction", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/ocr");
await page.goto("/image/ocr");
await page.waitForLoadState("networkidle");
try {
await page.getByTestId("ocr-submit").waitFor({ state: "visible", timeout: 15_000 });
+1 -1
View File
@@ -16,7 +16,7 @@ async function uploadFile(page: import("@playwright/test").Page, filePath: strin
test.describe("Passport Photo tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/passport-photo");
await page.goto("/image/passport-photo");
try {
// Wait for the page to load -- the country dropdown is always present
await page.getByText("Country").waitFor({ state: "visible", timeout: 15_000 });
+3 -3
View File
@@ -12,7 +12,7 @@ const PDF_FIXTURE = path.join(
test.describe("PDF to Image tool", () => {
test("shows page thumbnails after uploading a PDF", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
// Upload PDF via file input
const fileInput = page.locator("input[type='file'][accept='application/pdf']");
@@ -26,7 +26,7 @@ test.describe("PDF to Image tool", () => {
});
test("converts a PDF page to an image and shows results", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
// Upload PDF
const fileInput = page.locator("input[type='file'][accept='application/pdf']");
@@ -51,7 +51,7 @@ test.describe("PDF to Image tool", () => {
});
test("can select and deselect pages via thumbnails", async ({ loggedInPage: page }) => {
await page.goto("/pdf-to-image");
await page.goto("/pdf/pdf-to-image");
// Upload PDF
const fileInput = page.locator("input[type='file'][accept='application/pdf']");
+1 -1
View File
@@ -16,7 +16,7 @@ async function uploadFile(page: import("@playwright/test").Page, filePath: strin
test.describe("Red Eye Removal tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/red-eye-removal");
await page.goto("/image/red-eye-removal");
try {
await page
.getByTestId("red-eye-removal-submit")
+1 -1
View File
@@ -32,7 +32,7 @@ async function removeBgAndWait(page: import("@playwright/test").Page) {
test.describe("Remove Background tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/remove-background");
await page.goto("/image/remove-background");
try {
await page
.getByTestId("remove-background-submit")
+1 -1
View File
@@ -21,7 +21,7 @@ async function restoreAndWait(page: import("@playwright/test").Page) {
test.describe("Restore Photo tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/restore-photo");
await page.goto("/image/restore-photo");
try {
await page.getByTestId("restore-photo-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+1 -1
View File
@@ -16,7 +16,7 @@ async function uploadFile(page: import("@playwright/test").Page, filePath: strin
test.describe("Smart Crop tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/smart-crop");
await page.goto("/image/smart-crop");
try {
await page.getByTestId("smart-crop-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+11 -11
View File
@@ -3,7 +3,7 @@ import { expect, test, uploadTestImage, waitForProcessing } from "./helpers";
test.describe("Essential Tools", () => {
// ── Resize ────────────────────────────────────────────────────────────
test("resize tool page renders correctly", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Tool header
await expect(page.getByText("Resize").first()).toBeVisible();
@@ -13,7 +13,7 @@ test.describe("Essential Tools", () => {
});
test("resize tool shows settings after upload", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Should show settings panel with width/height inputs
@@ -23,7 +23,7 @@ test.describe("Essential Tools", () => {
});
test("resize tool processes an image", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Set width (required for resize)
@@ -39,52 +39,52 @@ test.describe("Essential Tools", () => {
// ── Crop ──────────────────────────────────────────────────────────────
test("crop tool page renders correctly", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await expect(page.getByText("Crop").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("crop tool shows settings after upload", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
});
// ── Rotate & Flip ────────────────────────────────────────────────────
test("rotate tool page renders correctly", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await expect(page.getByText("Rotate").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("rotate tool shows settings after upload", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
});
// ── Convert ───────────────────────────────────────────────────────────
test("convert tool page renders correctly", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await expect(page.getByText("Convert").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("convert tool shows format selector after upload", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
await expect(page.getByText("Settings").first()).toBeVisible();
});
// ── Compress ──────────────────────────────────────────────────────────
test("compress tool page renders correctly", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await expect(page.getByText("Compress").first()).toBeVisible();
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("compress tool processes an image", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Use submit button to avoid matching "Processed:" text
+15 -15
View File
@@ -7,7 +7,7 @@ import { expect, getTestHeicPath, test, uploadTestImage, waitForProcessing } fro
test.describe("Tool processing (core tools)", () => {
test("resize processes image", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
// Fill in width (required)
@@ -22,7 +22,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("compress processes image", async ({ loggedInPage: page }) => {
await page.goto("/compress");
await page.goto("/image/compress");
await uploadTestImage(page);
// Compress has defaults, just click
await page.getByRole("button", { name: "Compress" }).click();
@@ -33,7 +33,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("convert processes image", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
// Convert has a default format, just click
await page.getByRole("button", { name: /convert/i }).click();
@@ -44,7 +44,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("rotate processes image", async ({ loggedInPage: page }) => {
await page.goto("/rotate");
await page.goto("/image/rotate");
await uploadTestImage(page);
// Click the clockwise 90° rotation button and wait for state to propagate
await page.getByTestId("rotate-right").click();
@@ -61,7 +61,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("crop processes image", async ({ loggedInPage: page }) => {
await page.goto("/crop");
await page.goto("/image/crop");
await uploadTestImage(page);
// Wait for image to load in the crop canvas
await page.waitForTimeout(1000);
@@ -80,7 +80,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("strip-metadata processes image", async ({ loggedInPage: page }) => {
await page.goto("/strip-metadata");
await page.goto("/image/strip-metadata");
await uploadTestImage(page);
await page.getByRole("button", { name: /remove metadata/i }).click();
await waitForProcessing(page);
@@ -90,7 +90,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("edit-metadata processes image", async ({ loggedInPage: page }) => {
await page.goto("/edit-metadata");
await page.goto("/image/edit-metadata");
await uploadTestImage(page);
// Wait for inspect to complete and form to populate
@@ -121,7 +121,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("image-enhancement processes image", async ({ loggedInPage: page }) => {
await page.goto("/image-enhancement");
await page.goto("/image/image-enhancement");
await uploadTestImage(page);
// Wait for analysis to complete (badges appear)
await expect(
@@ -136,7 +136,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("border processes image", async ({ loggedInPage: page }) => {
await page.goto("/border");
await page.goto("/image/border");
await uploadTestImage(page);
// Default border width is 10px and color is #000000, should be valid
// Button text is "Apply Border" in border-settings.tsx
@@ -151,7 +151,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("info shows image metadata", async ({ loggedInPage: page }) => {
await page.goto("/info");
await page.goto("/image/info");
await uploadTestImage(page);
await page.getByRole("button", { name: /read info/i }).click();
await waitForProcessing(page);
@@ -162,7 +162,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("qr-generate creates QR code without file upload", async ({ loggedInPage: page }) => {
await page.goto("/qr-generate");
await page.goto("/image/qr-generate");
// Fill in URL input (client-side generation, live preview)
await page.getByTestId("qr-input-url").fill("https://example.com");
// Verify the live preview rendered (canvas or svg inside the preview area)
@@ -173,7 +173,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("vectorize processes image", async ({ loggedInPage: page }) => {
await page.goto("/vectorize");
await page.goto("/image/vectorize");
await uploadTestImage(page);
await page.getByRole("button", { name: /vectorize/i }).click();
await waitForProcessing(page);
@@ -183,7 +183,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("watermark-text processes image", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await page.goto("/image/watermark-text");
await uploadTestImage(page);
// Fill in watermark text
const textInput = page.locator("input[type='text'], textarea").first();
@@ -196,7 +196,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("convert HEIC to JPG", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
const heicPath = getTestHeicPath();
const fileChooserPromise = page.waitForEvent("filechooser");
@@ -216,7 +216,7 @@ test.describe("Tool processing (core tools)", () => {
});
test("convert PNG to HEIC", async ({ loggedInPage: page }) => {
await page.goto("/convert");
await page.goto("/image/convert");
await uploadTestImage(page);
// Select HEIC output format
+1 -1
View File
@@ -31,7 +31,7 @@ async function fixTransparencyAndWait(page: import("@playwright/test").Page) {
test.describe("PNG Transparency Fixer tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/transparency-fixer");
await page.goto("/image/transparency-fixer");
try {
await page
.getByTestId("transparency-fixer-submit")
+1 -1
View File
@@ -21,7 +21,7 @@ async function upscaleAndWait(page: import("@playwright/test").Page) {
test.describe("Upscale tool", () => {
async function skipIfFeatureNotInstalled(page: import("@playwright/test").Page) {
await page.goto("/upscale");
await page.goto("/image/upscale");
try {
await page.getByTestId("upscale-submit").waitFor({ state: "visible", timeout: 15_000 });
} catch {
+2 -2
View File
@@ -2,13 +2,13 @@ import { expect, test } from "./helpers";
test.describe("URL Image Import", () => {
test("inline URL input is visible on tool page", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
await expect(page.getByPlaceholder("Paste image URL...")).toBeVisible();
});
test("bulk import modal opens and closes", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await page.goto("/image/resize");
// Open the bulk import modal
await page.getByText("Import multiple URLs...").click();
+5 -5
View File
@@ -76,7 +76,7 @@ test.describe("Visual regression: Tool pages", () => {
test("resize tool - desktop (empty state)", async ({ loggedInPage: page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -88,7 +88,7 @@ test.describe("Visual regression: Tool pages", () => {
test("resize tool - desktop (with file uploaded)", async ({ loggedInPage: page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto("/resize");
await page.goto("/image/resize");
await uploadTestImage(page);
await page.waitForTimeout(500);
@@ -102,7 +102,7 @@ test.describe("Visual regression: Tool pages", () => {
test("resize tool - mobile (empty state)", async ({ loggedInPage: page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await page.goto("/resize");
await page.goto("/image/resize");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -114,7 +114,7 @@ test.describe("Visual regression: Tool pages", () => {
test("compress tool - desktop (empty state)", async ({ loggedInPage: page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto("/compress");
await page.goto("/image/compress");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);
@@ -126,7 +126,7 @@ test.describe("Visual regression: Tool pages", () => {
test("convert tool - desktop (empty state)", async ({ loggedInPage: page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto("/convert");
await page.goto("/image/convert");
await page.waitForLoadState("networkidle");
await page.waitForTimeout(500);