mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
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:
@@ -0,0 +1,81 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getCategoryName, getToolDescription, getToolName } from "@/lib/tool-i18n";
|
||||
|
||||
// Minimal mock shaped like TranslationKeys with tools and categories
|
||||
function makeT(
|
||||
tools: Record<string, { name?: string; description?: string }>,
|
||||
categories: Record<string, string>,
|
||||
) {
|
||||
return { tools, categories } as Parameters<typeof getToolName>[0];
|
||||
}
|
||||
|
||||
describe("getToolName", () => {
|
||||
const t = makeT(
|
||||
{
|
||||
resize: { name: "Resize Image", description: "Change dimensions" },
|
||||
compress: { name: "Compress" },
|
||||
"no-name": { description: "Only has description" },
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
it("returns translated name when available", () => {
|
||||
expect(getToolName(t, "resize", "Fallback")).toBe("Resize Image");
|
||||
});
|
||||
|
||||
it("returns fallback when tool entry has no name", () => {
|
||||
expect(getToolName(t, "no-name", "Fallback Name")).toBe("Fallback Name");
|
||||
});
|
||||
|
||||
it("returns fallback when tool id is not in translations", () => {
|
||||
expect(getToolName(t, "nonexistent", "Default Name")).toBe("Default Name");
|
||||
});
|
||||
|
||||
it("returns fallback for empty tool id", () => {
|
||||
expect(getToolName(t, "", "Empty Fallback")).toBe("Empty Fallback");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getToolDescription", () => {
|
||||
const t = makeT(
|
||||
{
|
||||
resize: { name: "Resize", description: "Change image dimensions" },
|
||||
"no-desc": { name: "Tool Without Desc" },
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
it("returns translated description when available", () => {
|
||||
expect(getToolDescription(t, "resize", "Fallback")).toBe("Change image dimensions");
|
||||
});
|
||||
|
||||
it("returns fallback when tool entry has no description", () => {
|
||||
expect(getToolDescription(t, "no-desc", "Default Desc")).toBe("Default Desc");
|
||||
});
|
||||
|
||||
it("returns fallback when tool id is not in translations", () => {
|
||||
expect(getToolDescription(t, "unknown", "Fallback Desc")).toBe("Fallback Desc");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCategoryName", () => {
|
||||
const t = makeT(
|
||||
{},
|
||||
{
|
||||
transform: "Transform",
|
||||
effects: "Effects & Filters",
|
||||
},
|
||||
);
|
||||
|
||||
it("returns translated category name when available", () => {
|
||||
expect(getCategoryName(t, "transform", "Fallback")).toBe("Transform");
|
||||
});
|
||||
|
||||
it("returns fallback when category id is not in translations", () => {
|
||||
expect(getCategoryName(t, "unknown-cat", "Unknown Category")).toBe("Unknown Category");
|
||||
});
|
||||
|
||||
it("returns fallback for empty category id", () => {
|
||||
expect(getCategoryName(t, "", "Empty")).toBe("Empty");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user