mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
test: expand unit test coverage (+437 tests, 17 new files)
Add comprehensive unit tests for previously uncovered API lib modules, web stores, and plugin functions. Fix 2 pre-existing editor-store test failures (invertSelection mask values). Coverage: 30.3% -> 36.85% stmts (unit), 57.71% stmts (integration).
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../../../apps/api/src/db/index.js", () => ({
|
||||
db: {
|
||||
select: () => ({
|
||||
from: () => ({ where: () => ({ get: () => null }) }),
|
||||
}),
|
||||
insert: () => ({ values: () => ({ run: vi.fn() }) }),
|
||||
},
|
||||
schema: { settings: {}, userFiles: {} },
|
||||
}));
|
||||
|
||||
vi.mock("../../../apps/api/src/config.js", () => ({
|
||||
env: {
|
||||
WORKSPACE_PATH: "/tmp/test",
|
||||
MAX_MEGAPIXELS: 100,
|
||||
MAX_SVG_SIZE_MB: 10,
|
||||
},
|
||||
}));
|
||||
|
||||
import type { AnyToolRouteConfig } from "../../../apps/api/src/routes/tool-factory.js";
|
||||
import {
|
||||
getRegisteredToolIds,
|
||||
getToolConfig,
|
||||
registerToolProcessFn,
|
||||
} from "../../../apps/api/src/routes/tool-factory.js";
|
||||
|
||||
const mockSchema = {
|
||||
safeParse: (data: unknown) => ({ success: true, data }),
|
||||
parse: (data: unknown) => data,
|
||||
};
|
||||
|
||||
const strictSchema = {
|
||||
safeParse: (data: unknown) => {
|
||||
const obj = data as Record<string, unknown>;
|
||||
if (typeof obj?.quality !== "number" || obj.quality < 1 || obj.quality > 100) {
|
||||
return { success: false, error: { issues: [{ message: "Invalid" }] } };
|
||||
}
|
||||
return { success: true, data };
|
||||
},
|
||||
parse: (data: unknown) => data,
|
||||
};
|
||||
|
||||
function makeMockConfig(toolId: string): AnyToolRouteConfig {
|
||||
return {
|
||||
toolId,
|
||||
settingsSchema: mockSchema as never,
|
||||
process: async (buf: Buffer, _settings: unknown, filename: string) => ({
|
||||
buffer: buf,
|
||||
filename,
|
||||
contentType: "image/png",
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
describe("tool-factory registry functions", () => {
|
||||
const uniqueId = () => `test-tool-${Math.random().toString(36).slice(2, 10)}`;
|
||||
|
||||
describe("registerToolProcessFn", () => {
|
||||
it("adds a tool to the registry", () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
expect(getToolConfig(id)).toBeDefined();
|
||||
});
|
||||
|
||||
it("stores the correct config", () => {
|
||||
const id = uniqueId();
|
||||
const config = makeMockConfig(id);
|
||||
registerToolProcessFn(config);
|
||||
const stored = getToolConfig(id);
|
||||
expect(stored?.toolId).toBe(id);
|
||||
expect(stored?.process).toBe(config.process);
|
||||
expect(stored?.settingsSchema).toBe(config.settingsSchema);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getToolConfig", () => {
|
||||
it("returns the config for a registered tool", () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
const config = getToolConfig(id);
|
||||
expect(config).toBeDefined();
|
||||
expect(config?.toolId).toBe(id);
|
||||
});
|
||||
|
||||
it("returns undefined for an unregistered tool", () => {
|
||||
expect(getToolConfig("nonexistent-tool-xyz-999")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getRegisteredToolIds", () => {
|
||||
it("includes a registered tool", () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
expect(getRegisteredToolIds()).toContain(id);
|
||||
});
|
||||
|
||||
it("includes multiple registered tools", () => {
|
||||
const id1 = uniqueId();
|
||||
const id2 = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id1));
|
||||
registerToolProcessFn(makeMockConfig(id2));
|
||||
const ids = getRegisteredToolIds();
|
||||
expect(ids).toContain(id1);
|
||||
expect(ids).toContain(id2);
|
||||
});
|
||||
|
||||
it("returns an array", () => {
|
||||
expect(Array.isArray(getRegisteredToolIds())).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("overwrite behavior", () => {
|
||||
it("later registration overwrites earlier for the same toolId", async () => {
|
||||
const id = uniqueId();
|
||||
const original = makeMockConfig(id);
|
||||
registerToolProcessFn(original);
|
||||
|
||||
const replacement: AnyToolRouteConfig = {
|
||||
toolId: id,
|
||||
settingsSchema: strictSchema as never,
|
||||
process: async (buf: Buffer, _settings: unknown, filename: string) => ({
|
||||
buffer: buf,
|
||||
filename: `replaced-${filename}`,
|
||||
contentType: "image/jpeg",
|
||||
}),
|
||||
};
|
||||
registerToolProcessFn(replacement);
|
||||
|
||||
const stored = getToolConfig(id);
|
||||
expect(stored?.process).toBe(replacement.process);
|
||||
expect(stored?.settingsSchema).toBe(replacement.settingsSchema);
|
||||
expect(stored?.process).not.toBe(original.process);
|
||||
});
|
||||
|
||||
it("overwriting does not change the count for that toolId", () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
const countBefore = getRegisteredToolIds().filter((x) => x === id).length;
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
const countAfter = getRegisteredToolIds().filter((x) => x === id).length;
|
||||
expect(countBefore).toBe(1);
|
||||
expect(countAfter).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("process function execution", () => {
|
||||
it("stored process function returns expected output", async () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn(makeMockConfig(id));
|
||||
const config = getToolConfig(id)!;
|
||||
const input = Buffer.from("test-data");
|
||||
const result = await config.process(input, {}, "photo.png");
|
||||
expect(result.buffer).toBe(input);
|
||||
expect(result.filename).toBe("photo.png");
|
||||
expect(result.contentType).toBe("image/png");
|
||||
});
|
||||
|
||||
it("stored process function with custom schema validates correctly", () => {
|
||||
const id = uniqueId();
|
||||
registerToolProcessFn({
|
||||
toolId: id,
|
||||
settingsSchema: strictSchema as never,
|
||||
process: async (buf, _s, fn) => ({ buffer: buf, filename: fn, contentType: "image/png" }),
|
||||
});
|
||||
const config = getToolConfig(id)!;
|
||||
const valid = config.settingsSchema.safeParse({ quality: 50 });
|
||||
expect(valid.success).toBe(true);
|
||||
const invalid = config.settingsSchema.safeParse({ quality: 200 });
|
||||
expect(invalid.success).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user