test: expand test coverage across unit, integration, e2e, and e2e-docker suites

Add ~210 new tests filling gaps identified by a comprehensive 14-agent
coverage audit. Unit+integration tests go from 9,388 to 9,484 (all passing).

Unit tests (+36):
- AI bridge: OOM fallback path, custom tier option
- Web lib: api-errors, format date/datetime, tool-i18n coverage

Integration tests (+19):
- Format matrix: ai-canvas-expand and find-duplicates added to cross-format matrix
- Adversarial: SVG XXE attacks, SQL injection in settings, request body size
  limits, race conditions with identical filenames

E2E Docker (+3):
- ai-canvas-expand tool coverage with HEIC input and edge cases

E2E GUI (~150+):
- Navigation: login rate limiting, ai-canvas-expand in parameterized list
- Responsive: dropzone visibility, text readability, dialog bounds at all viewports
- Keyboard: shortcuts verified from automate, files, tool, and fullscreen pages
- Tool UI: undo/state-reset for 16 tools, crop canvas drag handles, rotate/border
  live preview, linked aspect-ratio inputs for resize
- Batch: per-image undo isolation, batch compress/convert/rotate (not just resize)
- Pipeline: tool palette search, step collapse/expand visibility
- Settings: audit log entry verification, system settings persistence, teams CRUD,
  role permission toggling
- RBAC: user/editor 403 on roles/teams endpoints, privilege escalation prevention,
  cross-role tab parity documented as intentional
- Accessibility: skip-to-content link (WCAG 2.4.1), comprehensive color contrast
  for all headings/body/buttons in both themes with DOM-walking background detection
- Resilience: auth expiry 401 redirect, rate limit 429 handling
- Performance: JS heap memory stability for tool navigation, dialog cycling,
  upload/clear cycles, rapid page navigation
This commit is contained in:
SnapOtter
2026-05-15 21:35:02 +08:00
parent d38621d7b9
commit 3b181dd1ac
24 changed files with 3398 additions and 0 deletions
+71
View File
@@ -908,6 +908,77 @@ test.describe("Server Error Handling", () => {
await page.unroute("**/api/v1/tools/resize");
});
test("auth expiry (401) redirects to login or shows re-auth prompt", async ({
loggedInPage: page,
}) => {
await page.goto("/resize");
await uploadTestImage(page);
// Intercept to return 401 (session expired)
await page.route("**/api/v1/tools/resize", (route) =>
route.fulfill({
status: 401,
contentType: "application/json",
body: JSON.stringify({ error: "Session expired" }),
}),
);
await page.locator("input[placeholder='Auto']").first().fill("50");
await page.getByRole("button", { name: "Resize" }).click();
// Wait for error/redirect
await page.waitForTimeout(3000);
// Should either redirect to /login or show an auth error -- not crash
const url = page.url();
const bodyText = await page.textContent("body");
const redirectedToLogin = url.includes("/login");
const showsAuthError = /session|expired|unauthorized|login/i.test(bodyText ?? "");
expect(
redirectedToLogin || showsAuthError,
"Expected redirect to login or auth error message after 401",
).toBeTruthy();
// Page should not be a white screen
const content = await page.textContent("body");
expect(content).toBeDefined();
expect(content?.length).toBeGreaterThan(0);
await page.unroute("**/api/v1/tools/resize");
});
test("rate limit (429) shows throttle message, not crash", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await uploadTestImage(page);
// Intercept to return 429 (rate limited)
await page.route("**/api/v1/tools/resize", (route) =>
route.fulfill({
status: 429,
contentType: "application/json",
body: JSON.stringify({ error: "Rate limit exceeded. Try again later." }),
}),
);
await page.locator("input[placeholder='Auto']").first().fill("50");
await page.getByRole("button", { name: "Resize" }).click();
// Wait for error to appear
await page.waitForTimeout(3000);
// Page should not crash
await expect(page.locator("main")).toBeVisible();
await expect(page.locator("aside")).toBeVisible();
// Body should contain meaningful content (not blank)
const bodyText = await page.textContent("body");
expect(bodyText).toBeDefined();
expect(bodyText?.length).toBeGreaterThan(0);
await page.unroute("**/api/v1/tools/resize");
});
test("network timeout shows error, not infinite spinner", async ({ loggedInPage: page }) => {
await page.goto("/resize");
await uploadTestImage(page);