mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
Exhaustive QA sweep of all 157 tools. Fixes: CSP blob media, csv-excel ExcelJS interop, ocr-pdf segfault, chart-maker upload, non-PDF doc preview, RAW decode, merge-tool multi-file path, html-to-image chromium, ogv/wma/amr/ac3 preview fallbacks, meme/gif/stabilize codecs, nav+home a11y. Plus orphan-format and test-debt cleanup, the AI bundle build script, and a reusable Playwright QA harness under tests/qa/.
75 lines
2.9 KiB
TypeScript
75 lines
2.9 KiB
TypeScript
import {
|
|
detectModalityFromMime,
|
|
MODALITIES,
|
|
MODALITY_POOL,
|
|
PYTHON_SIDECAR_TOOLS,
|
|
TOOLS,
|
|
} from "@snapotter/shared";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
describe("modality metadata", () => {
|
|
it("defines five modalities with UI metadata", () => {
|
|
expect(MODALITIES.map((m) => m.id)).toEqual(["image", "video", "audio", "document", "file"]);
|
|
for (const m of MODALITIES) {
|
|
expect(m.name).toBeTruthy();
|
|
expect(m.icon).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
it("maps every modality to a worker pool", () => {
|
|
expect(MODALITY_POOL.image).toBe("image");
|
|
expect(MODALITY_POOL.video).toBe("media");
|
|
expect(MODALITY_POOL.audio).toBe("media");
|
|
expect(MODALITY_POOL.document).toBe("docs");
|
|
expect(MODALITY_POOL.file).toBe("docs");
|
|
});
|
|
|
|
it("every tool declares a valid modality, acceptedInputs and executionHint", () => {
|
|
const validModalities = ["image", "video", "audio", "document", "file"];
|
|
expect(TOOLS.length).toBeGreaterThanOrEqual(53);
|
|
for (const tool of TOOLS) {
|
|
expect(validModalities).toContain(tool.modality);
|
|
expect(Array.isArray(tool.acceptedInputs)).toBe(true);
|
|
// Empty acceptedInputs is valid for file-modality tools that accept any file
|
|
// (e.g. create-zip); the factory 415 gate skips when the list is empty.
|
|
if (tool.modality !== "file" || tool.acceptedInputs.length > 0) {
|
|
expect(tool.acceptedInputs.length).toBeGreaterThan(0);
|
|
}
|
|
expect(["fast", "long"]).toContain(tool.executionHint);
|
|
}
|
|
});
|
|
|
|
it("pdf-to-image is a document-modality tool", () => {
|
|
const pdfToImage = TOOLS.find((t) => t.id === "pdf-to-image");
|
|
expect(pdfToImage).toBeDefined();
|
|
expect(pdfToImage!.modality).toBe("document");
|
|
expect(pdfToImage!.category).toBe("pdf-organize");
|
|
expect(pdfToImage!.acceptedInputs).toEqual([".pdf"]);
|
|
});
|
|
|
|
it("AI (sidecar) tools are hinted long (except pure-CV ones)", () => {
|
|
const sidecar = new Set<string>(PYTHON_SIDECAR_TOOLS as readonly string[]);
|
|
const ai = TOOLS.filter((t) => sidecar.has(t.id));
|
|
expect(ai.length).toBeGreaterThan(0);
|
|
// image-enhancement uses pure sharp/CV (only the optional deepEnhance hits a
|
|
// model); it is not a sidecar tool, but keep the guard explicit.
|
|
const pureCvAiTools = new Set(["image-enhancement"]);
|
|
for (const t of ai) {
|
|
if (pureCvAiTools.has(t.id)) {
|
|
expect(t.executionHint).toBe("fast");
|
|
} else {
|
|
expect(t.executionHint).toBe("long");
|
|
}
|
|
}
|
|
});
|
|
|
|
it("detects modality from mime", () => {
|
|
expect(detectModalityFromMime("image/png")).toBe("image");
|
|
expect(detectModalityFromMime("video/mp4")).toBe("video");
|
|
expect(detectModalityFromMime("audio/mpeg")).toBe("audio");
|
|
expect(detectModalityFromMime("application/pdf")).toBe("document");
|
|
expect(detectModalityFromMime("text/csv")).toBe("file");
|
|
expect(detectModalityFromMime("")).toBe("file");
|
|
});
|
|
});
|