Merge fix/131-content-aware-resize-registry: add frontend registry for content-aware resize

fix: add frontend registry entry for content-aware resize tool

Closes #131
This commit is contained in:
SnapOtter
2026-05-07 09:44:14 +08:00
4 changed files with 297 additions and 0 deletions
+31
View File
@@ -33,6 +33,37 @@ async function enableContentAware(page: import("@playwright/test").Page) {
}
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");
// Must NOT show "Tool not found"
await expect(page.getByText("Tool not found")).not.toBeVisible();
// Must show the tool name and content-aware controls
await expect(page.getByText("Content-Aware Resize")).toBeVisible();
await expect(page.getByText("Resize to square")).toBeVisible();
await expect(page.getByText("Protect faces")).toBeVisible();
await expect(page.getByText("Smoothing")).toBeVisible();
await expect(page.getByText("Edge sensitivity")).toBeVisible();
});
test("direct route submit disabled without file", async ({ loggedInPage: page }) => {
await page.goto("/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 uploadFile(page, fixturePath("test-200x150.png"));
const widthInput = page.locator("input[placeholder='Auto']").first();
await widthInput.fill("150");
await expect(page.getByTestId("content-aware-resize-submit")).toBeEnabled();
});
test("content-aware toggle reveals seam carving controls", async ({ loggedInPage: page }) => {
await page.goto("/resize");
+28
View File
@@ -163,11 +163,18 @@ vi.mock("@/components/tools/red-eye-removal-settings", () => ({
vi.mock("@/components/tools/restore-photo-settings", () => ({
RestorePhotoSettings: () => null,
}));
vi.mock("@/components/tools/transparency-fixer-settings", () => ({
TransparencyFixerSettings: () => null,
}));
vi.mock("@/components/tools/content-aware-resize-settings", () => ({
ContentAwareResizeSettings: () => null,
}));
// ---------------------------------------------------------------------------
// Import after mocks
// ---------------------------------------------------------------------------
import { TOOLS } from "@snapotter/shared";
import type { DisplayMode } from "@/lib/tool-registry";
import { getToolRegistryEntry, toolRegistry } from "@/lib/tool-registry";
@@ -211,6 +218,7 @@ describe("toolRegistry", () => {
"passport-photo",
"red-eye-removal",
"restore-photo",
"content-aware-resize",
];
for (const id of aiTools) {
expect(toolRegistry.has(id), `missing AI tool: ${id}`).toBe(true);
@@ -324,6 +332,19 @@ describe("toolRegistry", () => {
const split = toolRegistry.get("split");
expect(split?.displayMode).toBe("interactive-split");
});
it("every tool in shared TOOLS[] has a matching registry entry", () => {
const missing: string[] = [];
for (const tool of TOOLS) {
if (!toolRegistry.has(tool.id)) {
missing.push(tool.id);
}
}
expect(
missing,
`Tools defined in TOOLS[] but missing from toolRegistry: ${missing.join(", ")}`,
).toEqual([]);
});
});
// ==========================================================================
@@ -360,6 +381,13 @@ describe("getToolRegistryEntry", () => {
expect(entry?.displayMode).toBe("no-dropzone");
expect(entry?.ResultsPanel).toBeDefined();
});
it("returns entry for content-aware-resize with side-by-side display (regression #131)", () => {
const entry = getToolRegistryEntry("content-aware-resize");
expect(entry).toBeDefined();
expect(entry?.displayMode).toBe("side-by-side");
expect(entry?.Settings).toBeDefined();
});
});
// ==========================================================================