test: expand test coverage across all layers (+1,157 tests)

Fix 2 failing unit tests (landing hero text mismatch) and broken
coverage tooling (brace-expansion v5 override breaking minimatch).
Add ~1,097 new test cases via 14-agent parallel expansion:

- Unit: +290 tests (AI bridge, image-engine, stores, API helpers)
- Integration: +504 tests (all tools, cross-format matrix, adversarial)
- E2E: +363 tests (navigation, tool UI, batch/pipeline, settings,
  visual regression, accessibility, performance, cross-browser)

Total: 4,223 unit + 6,057 integration + 1,563 E2E = 11,843 tests
This commit is contained in:
SnapOtter
2026-06-06 19:37:29 +08:00
parent 66e503730d
commit 06d1822491
67 changed files with 20114 additions and 49 deletions
+350
View File
@@ -1148,4 +1148,354 @@ test.describe("Mobile Navigation", () => {
await context.close();
});
test("hamburger menu Grid link navigates to /fullscreen", async ({ browser }) => {
const context = await browser.newContext({
viewport: { width: 375, height: 667 },
});
const page = await context.newPage();
await page.goto("/login");
await page.getByLabel("Username").fill("admin");
await page.getByLabel("Password").fill("admin");
await page.getByRole("button", { name: /login/i }).click();
await page.waitForURL("/", { timeout: 15_000 });
// Open hamburger menu
const topBar = page.locator(".fixed").filter({ hasText: "SnapOtter" }).first();
const hamburger = topBar.locator("button").first();
await hamburger.click();
// Click Grid in expanded sidebar
await page.getByText("Grid").click();
await expect(page).toHaveURL("/fullscreen");
await context.close();
});
test("hamburger menu Automate link navigates to /automate", async ({ browser }) => {
const context = await browser.newContext({
viewport: { width: 375, height: 667 },
});
const page = await context.newPage();
await page.goto("/login");
await page.getByLabel("Username").fill("admin");
await page.getByLabel("Password").fill("admin");
await page.getByRole("button", { name: /login/i }).click();
await page.waitForURL("/", { timeout: 15_000 });
const topBar = page.locator(".fixed").filter({ hasText: "SnapOtter" }).first();
const hamburger = topBar.locator("button").first();
await hamburger.click();
await page.getByText("Automate").nth(1).click();
await expect(page).toHaveURL("/automate");
await context.close();
});
});
// ---------------------------------------------------------------------------
// Editor Page (/editor)
// ---------------------------------------------------------------------------
test.describe("Editor Page", () => {
test("editor page renders with canvas area", async ({ loggedInPage: page }) => {
await page.goto("/editor");
await expect(page).toHaveURL("/editor");
// Editor should have a canvas or main editor area
await expect(page.getByText(/editor|canvas|draw/i).first()).toBeVisible();
});
test("editor page is accessible from sidebar", async ({ loggedInPage: page }) => {
await page.locator("aside").getByText("Editor").click();
await expect(page).toHaveURL("/editor");
});
test("page refresh preserves /editor route", async ({ loggedInPage: page }) => {
await page.goto("/editor");
await expect(page).toHaveURL("/editor");
await page.reload();
await expect(page).toHaveURL("/editor");
});
});
// ---------------------------------------------------------------------------
// Settings Dialog - Tab Navigation
// ---------------------------------------------------------------------------
test.describe("Settings Dialog Tabs", () => {
test("settings dialog shows all navigation sections", async ({ loggedInPage: page }) => {
await openSettings(page);
// Core sections should be listed in nav
await expect(page.getByRole("button", { name: "General" })).toBeVisible();
await expect(page.getByRole("button", { name: "Security" })).toBeVisible();
await expect(page.getByRole("button", { name: "About" })).toBeVisible();
});
test("clicking Security tab shows security settings", async ({ loggedInPage: page }) => {
await openSettings(page);
await page.getByRole("button", { name: "Security" }).click();
await page.waitForTimeout(300);
// Security section content should appear
await expect(page.getByRole("heading", { name: "Security" })).toBeVisible();
});
test("clicking About tab shows version info", async ({ loggedInPage: page }) => {
await openSettings(page);
await page.getByRole("button", { name: "About" }).click();
await page.waitForTimeout(300);
// About section should show version
await expect(page.getByText(/version/i).first()).toBeVisible();
});
test("switching between tabs preserves dialog open state", async ({ loggedInPage: page }) => {
await openSettings(page);
// Switch to Security
await page.getByRole("button", { name: "Security" }).click();
await page.waitForTimeout(200);
await expect(page.getByRole("dialog")).toBeVisible();
// Switch to About
await page.getByRole("button", { name: "About" }).click();
await page.waitForTimeout(200);
await expect(page.getByRole("dialog")).toBeVisible();
// Switch back to General
await page.getByRole("button", { name: "General" }).click();
await page.waitForTimeout(200);
await expect(page.getByRole("dialog")).toBeVisible();
await expect(page.getByRole("heading", { name: "General" })).toBeVisible();
});
});
// ---------------------------------------------------------------------------
// Language Selector
// ---------------------------------------------------------------------------
test.describe("Language Selector", () => {
test("language button opens language dropdown", async ({ loggedInPage: page }) => {
const langBtn = page.locator("button[title='Language']");
await expect(langBtn).toBeVisible();
await langBtn.click();
await page.waitForTimeout(300);
// Language options should appear
await expect(page.getByText(/espa|fran|deutsch|portugu/i).first()).toBeVisible();
});
test("selecting a language updates the button label", async ({ loggedInPage: page }) => {
const langBtn = page.locator("button[title='Language']");
await expect(langBtn).toContainText("English");
await langBtn.click();
await page.waitForTimeout(300);
// Pick a different language and check the button updates
const spanishOption = page.getByText(/espa/i).first();
if (await spanishOption.isVisible({ timeout: 3000 }).catch(() => false)) {
await spanishOption.click();
await page.waitForTimeout(500);
// Button should no longer say "English"
await expect(langBtn).not.toContainText("English");
// Reset back to English
await langBtn.click();
await page.waitForTimeout(300);
await page.getByText("English").first().click();
}
});
});
// ---------------------------------------------------------------------------
// Fullscreen Grid - Tool Visibility
// ---------------------------------------------------------------------------
test.describe("Fullscreen Grid - AI Tool Visibility", () => {
test("AI tools section is visible in fullscreen grid", async ({ loggedInPage: page }) => {
await page.goto("/fullscreen");
await expect(page.getByText("AI Tools")).toBeVisible();
// At least one AI tool should be listed
await expect(page.getByRole("link", { name: /Remove Background/ }).first()).toBeVisible();
});
test("tool cards display an icon and name", async ({ loggedInPage: page }) => {
await page.goto("/fullscreen");
// A tool card should have visible text for its name
const resizeLink = page.getByRole("link", { name: /^Resize/ }).first();
await expect(resizeLink).toBeVisible();
// And it should contain an SVG icon
await expect(resizeLink.locator("svg").first()).toBeVisible();
});
});
// ---------------------------------------------------------------------------
// Automate Page - Additional Coverage
// ---------------------------------------------------------------------------
test.describe("Automate Page - Pipeline Management", () => {
test("removing a pipeline step returns to empty state", async ({ loggedInPage: page }) => {
await page.goto("/automate");
// Add a tool step
const resizeTool = page.locator("[data-tool-id='resize']").first();
if (await resizeTool.isVisible({ timeout: 3000 }).catch(() => false)) {
await resizeTool.click();
} else {
await page.getByText("Resize").first().click();
}
await page.waitForTimeout(500);
// Step should be added
await expect(page.getByText("No steps yet")).not.toBeVisible();
// Remove the step (click the remove/delete button on the step)
const removeBtn = page
.locator("button")
.filter({ has: page.locator("svg") })
.filter({
hasText: /remove|delete|x/i,
})
.first();
if (await removeBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
await removeBtn.click();
await page.waitForTimeout(300);
await expect(page.getByText("No steps yet")).toBeVisible();
}
});
test("adding multiple steps shows ordered step list", async ({ loggedInPage: page }) => {
await page.goto("/automate");
// Add first tool
const resizeTool = page.locator("[data-tool-id='resize']").first();
if (await resizeTool.isVisible({ timeout: 3000 }).catch(() => false)) {
await resizeTool.click();
} else {
await page.getByText("Resize").first().click();
}
await page.waitForTimeout(300);
// Add second tool
const compressTool = page.locator("[data-tool-id='compress']").first();
if (await compressTool.isVisible({ timeout: 3000 }).catch(() => false)) {
await compressTool.click();
} else {
await page.getByText("Compress").first().click();
}
await page.waitForTimeout(300);
// Both tools should be listed as steps
await expect(page.getByText("Resize").first()).toBeVisible();
await expect(page.getByText("Compress").first()).toBeVisible();
});
});
// ---------------------------------------------------------------------------
// Routing - Additional Edge Cases
// ---------------------------------------------------------------------------
test.describe("Routing - Additional Edge Cases", () => {
test("/change-password page renders for authenticated user", async ({ loggedInPage: page }) => {
await page.goto("/change-password");
// Should render the change password form
await expect(page.getByText(/change password|new password/i).first()).toBeVisible();
});
test("navigating to /editor and back preserves home state", async ({ loggedInPage: page }) => {
// Start at home
await expect(page).toHaveURL("/");
// Navigate to editor
await page.goto("/editor");
await expect(page).toHaveURL("/editor");
// Navigate back
await page.goBack();
await expect(page).toHaveURL("/");
// Home content should be intact
await expect(page.getByText("Upload from computer")).toBeVisible();
});
test("deep-linking to a specific tool page works", async ({ loggedInPage: page }) => {
await page.goto("/watermark-text");
await expect(page).toHaveURL("/watermark-text");
await expect(page.getByText("Text Watermark").first()).toBeVisible();
});
test("double navigation to same page does not break state", async ({ loggedInPage: page }) => {
await page.goto("/fullscreen");
await expect(page).toHaveURL("/fullscreen");
await page.goto("/fullscreen");
await expect(page).toHaveURL("/fullscreen");
// Page should still work correctly
await expect(page.getByPlaceholder(/search/i)).toBeVisible();
});
test("navigating from a legacy redirect to another page works", async ({
loggedInPage: page,
}) => {
await page.goto("/brightness-contrast");
await expect(page).toHaveURL("/adjust-colors");
await page.goto("/fullscreen");
await expect(page).toHaveURL("/fullscreen");
await page.goBack();
await expect(page).toHaveURL("/adjust-colors");
});
});
// ---------------------------------------------------------------------------
// Tool Page - Mobile Structure (375x667)
// ---------------------------------------------------------------------------
test.describe("Tool Page - Mobile Structure", () => {
const MOBILE_TOOLS = [
{ id: "resize", name: "Resize" },
{ id: "compress", name: "Compress" },
{ id: "convert", name: "Convert" },
{ id: "crop", name: "Crop" },
{ id: "watermark-text", name: "Text Watermark" },
{ id: "adjust-colors", name: "Adjust Colors" },
];
for (const tool of MOBILE_TOOLS) {
test(`mobile: ${tool.name} (/${tool.id}) shows tool name and dropzone`, async ({ browser }) => {
const context = await browser.newContext({
viewport: { width: 375, height: 667 },
});
const page = await context.newPage();
await page.goto("/login");
await page.getByLabel("Username").fill("admin");
await page.getByLabel("Password").fill("admin");
await page.getByRole("button", { name: /login/i }).click();
await page.waitForURL("/", { timeout: 15_000 });
await page.goto(`/${tool.id}`);
// Tool name should be visible
await expect(page.getByText(tool.name).first()).toBeVisible();
// Dropzone should be visible on mobile too
const dropzone = page.locator("[class*='border-dashed']").first();
await expect(dropzone).toBeVisible();
// No horizontal overflow
const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth);
const clientWidth = await page.evaluate(() => document.documentElement.clientWidth);
expect(scrollWidth).toBeLessThanOrEqual(clientWidth);
await context.close();
});
}
});