Files
SnapOtter/tests/unit/shared/features.test.ts
T
SnapOtter 1727a7a73e test: reorganize flat test files into purpose-based subdirectories (phase 6)
Group 245 flat integration tests and 25 loose unit tests into
discoverable subdirectories per spec section 6:

  integration/tools/{image,video,audio,document,data}/  (156 files)
  integration/platform/                                  (64 files)
  integration/generated/                                 (14 files)
  integration/security/                                  (10 files)

  unit/security/     (8 files, new subdir)
  unit/api/          (7 files moved in)
  unit/web/          (3 files moved in)
  unit/shared/       (6 files moved in)
  unit/image-engine/ (1 file moved in)

All moves via git mv (history preserved). Relative imports repaired
for both depth levels (platform/generated/security = +1, tools/ = +2):
static from-imports, dynamic import() calls, vi.mock() paths,
import.meta.dirname joins, and __dirname joins.

Vitest discovery unchanged (no test.include in config, recursive glob
matches subdirs, shard-by-hash unaffected). test-server.ts and
tool-route-drift.test.ts stay at integration root. fixtures/ untouched.

Parity gate: 13189 passing test names before = 13189 after (0 dropped).
2026-06-20 05:07:46 +08:00

103 lines
3.5 KiB
TypeScript

import {
FEATURE_BUNDLES,
getBundleForTool,
getToolsForBundle,
PYTHON_SIDECAR_TOOLS,
TOOL_BUNDLE_MAP,
} from "@snapotter/shared";
import { describe, expect, it } from "vitest";
describe("Feature bundles", () => {
it("every PYTHON_SIDECAR_TOOL maps to exactly one bundle", () => {
for (const toolId of PYTHON_SIDECAR_TOOLS) {
const bundle = getBundleForTool(toolId);
expect(bundle, `${toolId} has no bundle`).toBeDefined();
}
});
it("getBundleForTool returns null for non-AI tools", () => {
expect(getBundleForTool("resize")).toBeNull();
expect(getBundleForTool("crop")).toBeNull();
});
it("getToolsForBundle returns correct tools", () => {
const tools = getToolsForBundle("background-removal");
expect(tools).toContain("remove-background");
expect(tools).toContain("passport-photo");
expect(tools).not.toContain("upscale");
});
it("all 7 bundles are defined", () => {
expect(Object.keys(FEATURE_BUNDLES)).toHaveLength(7);
expect(FEATURE_BUNDLES["background-removal"]).toBeDefined();
expect(FEATURE_BUNDLES["face-detection"]).toBeDefined();
expect(FEATURE_BUNDLES["object-eraser-colorize"]).toBeDefined();
expect(FEATURE_BUNDLES["upscale-enhance"]).toBeDefined();
expect(FEATURE_BUNDLES["photo-restoration"]).toBeDefined();
expect(FEATURE_BUNDLES.ocr).toBeDefined();
expect(FEATURE_BUNDLES.transcription).toBeDefined();
});
it("TOOL_BUNDLE_MAP covers all sidecar tools", () => {
const mappedTools = Object.keys(TOOL_BUNDLE_MAP);
for (const toolId of PYTHON_SIDECAR_TOOLS) {
expect(mappedTools, `${toolId} missing from TOOL_BUNDLE_MAP`).toContain(toolId);
}
});
});
describe("Feature bundle edge cases", () => {
it("no duplicate tools across bundles", () => {
const allTools: string[] = [];
for (const bundle of Object.values(FEATURE_BUNDLES)) {
for (const tool of bundle.enablesTools) {
expect(allTools, `Tool ${tool} appears in multiple bundles`).not.toContain(tool);
allTools.push(tool);
}
}
});
it("every bundle has a non-empty estimated size", () => {
for (const bundle of Object.values(FEATURE_BUNDLES)) {
expect(bundle.estimatedSize.length).toBeGreaterThan(0);
}
});
it("getToolsForBundle returns empty array for unknown bundle", () => {
expect(getToolsForBundle("nonexistent")).toEqual([]);
});
it("getBundleForTool returns null for unknown tool", () => {
expect(getBundleForTool("nonexistent-tool")).toBeNull();
});
it("TOOL_BUNDLE_MAP has no undefined values", () => {
for (const [tool, bundle] of Object.entries(TOOL_BUNDLE_MAP)) {
expect(bundle, `Tool ${tool} has undefined bundle`).toBeDefined();
expect(
FEATURE_BUNDLES[bundle],
`Bundle ${bundle} for tool ${tool} not in FEATURE_BUNDLES`,
).toBeDefined();
}
});
it("every bundle id matches its key in FEATURE_BUNDLES", () => {
for (const [key, bundle] of Object.entries(FEATURE_BUNDLES)) {
expect(bundle.id).toBe(key);
}
});
it("every bundle has a non-empty name and description", () => {
for (const bundle of Object.values(FEATURE_BUNDLES)) {
expect(bundle.name.length).toBeGreaterThan(0);
expect(bundle.description.length).toBeGreaterThan(0);
}
});
it("every bundle has at least one tool", () => {
for (const [id, bundle] of Object.entries(FEATURE_BUNDLES)) {
expect(bundle.enablesTools.length, `Bundle ${id} has no tools`).toBeGreaterThan(0);
}
});
});