Files
SnapOtter/tests/unit/api/static-upload.test.ts
T
SnapOtter 649ad5db9e test: massive test coverage expansion (+1,437 tests, 22 new files)
Expand test coverage across all layers via 14 parallel agents:

Unit tests (3,378 total, +534):
- First-ever AI sidecar tests (157 tests covering bridge lifecycle, all 12 tool modules)
- API route infrastructure (auth, pipeline, batch, settings, teams, roles, audit, api-keys, files, docs)
- Lib coverage improvements (audit 7%->95%, worker-pool 33%->100%)
- Web store/lib gap fills (features-store, tool-registry)

Integration tests (4,403 total, +903):
- Expanded 19 tool test files with parameter variations, format edge cases, boundary values
- Cross-format matrix: 290 tests covering 14 tools x 17 formats
- Adversarial/edge cases: 63 tests for extreme inputs, concurrent requests, corrupted files

E2E-Docker (125 new tests):
- Expanded 8 spec files + 1 new file covering all 49 tools
- Added HEIC/format handling, auth failures, download verification

GUI E2E (expanded 28 spec files):
- Navigation, responsive layout, keyboard shortcuts
- All 51 tool UIs with settings, processing, display modes
- Batch/pipeline workflows, settings/RBAC, visual regression
- Resilience, accessibility (ARIA, contrast, focus), performance budgets
2026-05-09 09:02:29 +08:00

170 lines
5.5 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const uploadConfig = vi.hoisted(() => ({
MAX_UPLOAD_SIZE_MB: 10,
MAX_BATCH_SIZE: 5,
}));
vi.mock("../../../apps/api/src/config.js", () => ({ env: uploadConfig }));
const _mockStaticRegister = vi.fn().mockResolvedValue(undefined);
vi.mock("@fastify/static", () => ({ default: "fastify-static-plugin" }));
const mockMultipartPlugin = vi.fn();
vi.mock("@fastify/multipart", () => ({ default: mockMultipartPlugin }));
vi.mock("node:fs", async (importOriginal) => {
const actual = (await importOriginal()) as Record<string, unknown>;
return {
...actual,
existsSync: vi.fn(() => true),
};
});
describe("registerStatic", () => {
let registerStatic: typeof import("../../../apps/api/src/plugins/static.js").registerStatic;
let existsSyncMock: ReturnType<typeof vi.fn>;
beforeEach(async () => {
vi.clearAllMocks();
const staticModule = await import("../../../apps/api/src/plugins/static.js");
registerStatic = staticModule.registerStatic;
const fsMod = await import("node:fs");
existsSyncMock = fsMod.existsSync as ReturnType<typeof vi.fn>;
});
it("registers static plugin when dist path exists", async () => {
existsSyncMock.mockReturnValue(true);
const app = {
register: vi.fn().mockResolvedValue(undefined),
setNotFoundHandler: vi.fn(),
log: { warn: vi.fn() },
};
await registerStatic(app as never);
expect(app.register).toHaveBeenCalledWith("fastify-static-plugin", {
root: expect.stringContaining("web/dist"),
prefix: "/",
wildcard: false,
});
expect(app.setNotFoundHandler).toHaveBeenCalled();
});
it("sets SPA not-found handler that returns 404 for API routes", async () => {
existsSyncMock.mockReturnValue(true);
let notFoundHandler: (request: unknown, reply: unknown) => void;
const app = {
register: vi.fn().mockResolvedValue(undefined),
setNotFoundHandler: vi.fn((handler: typeof notFoundHandler) => {
notFoundHandler = handler;
}),
log: { warn: vi.fn() },
};
await registerStatic(app as never);
const reply = { code: vi.fn().mockReturnThis(), send: vi.fn(), sendFile: vi.fn() };
notFoundHandler?.({ url: "/api/v1/tools" }, reply);
expect(reply.code).toHaveBeenCalledWith(404);
expect(reply.send).toHaveBeenCalledWith({ error: "Not found", code: "NOT_FOUND" });
});
it("sets SPA not-found handler that serves index.html for non-API routes", async () => {
existsSyncMock.mockReturnValue(true);
let notFoundHandler: (request: unknown, reply: unknown) => void;
const app = {
register: vi.fn().mockResolvedValue(undefined),
setNotFoundHandler: vi.fn((handler: typeof notFoundHandler) => {
notFoundHandler = handler;
}),
log: { warn: vi.fn() },
};
await registerStatic(app as never);
const reply = { code: vi.fn().mockReturnThis(), send: vi.fn(), sendFile: vi.fn() };
notFoundHandler?.({ url: "/resize" }, reply);
expect(reply.sendFile).toHaveBeenCalledWith("index.html");
});
it("logs warning and skips registration when dist path does not exist", async () => {
existsSyncMock.mockReturnValue(false);
const app = {
register: vi.fn().mockResolvedValue(undefined),
setNotFoundHandler: vi.fn(),
log: { warn: vi.fn() },
};
await registerStatic(app as never);
expect(app.log.warn).toHaveBeenCalledWith(expect.stringContaining("SPA dist not found"));
expect(app.register).not.toHaveBeenCalled();
expect(app.setNotFoundHandler).not.toHaveBeenCalled();
});
});
describe("registerUpload", () => {
let registerUpload: typeof import("../../../apps/api/src/plugins/upload.js").registerUpload;
beforeEach(async () => {
vi.clearAllMocks();
const uploadModule = await import("../../../apps/api/src/plugins/upload.js");
registerUpload = uploadModule.registerUpload;
});
it("registers multipart with correct file size limit", async () => {
uploadConfig.MAX_UPLOAD_SIZE_MB = 10;
uploadConfig.MAX_BATCH_SIZE = 5;
const app = { register: vi.fn().mockResolvedValue(undefined) };
await registerUpload(app as never);
expect(app.register).toHaveBeenCalledWith(mockMultipartPlugin, {
limits: {
fileSize: 10 * 1024 * 1024,
files: 5,
},
});
});
it("passes undefined for fileSize when MAX_UPLOAD_SIZE_MB is 0", async () => {
uploadConfig.MAX_UPLOAD_SIZE_MB = 0;
uploadConfig.MAX_BATCH_SIZE = 5;
const app = { register: vi.fn().mockResolvedValue(undefined) };
await registerUpload(app as never);
expect(app.register).toHaveBeenCalledWith(mockMultipartPlugin, {
limits: {
fileSize: undefined,
files: 5,
},
});
});
it("passes undefined for files when MAX_BATCH_SIZE is 0", async () => {
uploadConfig.MAX_UPLOAD_SIZE_MB = 10;
uploadConfig.MAX_BATCH_SIZE = 0;
const app = { register: vi.fn().mockResolvedValue(undefined) };
await registerUpload(app as never);
expect(app.register).toHaveBeenCalledWith(mockMultipartPlugin, {
limits: {
fileSize: 10 * 1024 * 1024,
files: undefined,
},
});
});
it("passes undefined for both limits when both are 0", async () => {
uploadConfig.MAX_UPLOAD_SIZE_MB = 0;
uploadConfig.MAX_BATCH_SIZE = 0;
const app = { register: vi.fn().mockResolvedValue(undefined) };
await registerUpload(app as never);
expect(app.register).toHaveBeenCalledWith(mockMultipartPlugin, {
limits: {
fileSize: undefined,
files: undefined,
},
});
});
});