multica/vitest.setup.ts
Jiayuan Zhang f525d6ccfe test: add vitest setup with static mock policy checker
Scans test files at startup and warns when vi.mock() targets internal
modules (relative paths or @multica/* packages). Reports file paths
and line numbers for all violations without interfering with test
execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:03:36 +08:00

72 lines
2.2 KiB
TypeScript

/**
* Vitest global setup — statically scans test files for internal mock violations.
*
* Rule: only mock third-party / external dependencies.
* Internal modules (relative imports, @multica/* packages) must NOT be mocked.
*
* This runs once at startup and logs warnings for violations without
* interfering with vitest's mock hoisting mechanism.
*/
import { readFileSync, readdirSync, statSync } from "node:fs";
import { join, resolve } from "node:path";
const INTERNAL_MOCK_PATTERN =
/vi\.mock\(\s*["'](\.\/|\.\.\/|@multica\/)[^"']*["']/g;
function scanDirectory(dir: string): string[] {
const files: string[] = [];
try {
for (const entry of readdirSync(dir)) {
const full = join(dir, entry);
const stat = statSync(full, { throwIfNoEntry: false });
if (!stat) continue;
if (stat.isDirectory() && entry !== "node_modules") {
files.push(...scanDirectory(full));
} else if (entry.endsWith(".test.ts")) {
files.push(full);
}
}
} catch {
// ignore unreadable directories
}
return files;
}
function checkMockPolicy(): void {
const srcDir = resolve(process.cwd(), "src");
const testFiles = scanDirectory(srcDir);
const violations: Array<{ file: string; line: number; match: string }> = [];
for (const file of testFiles) {
const content = readFileSync(file, "utf-8");
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
INTERNAL_MOCK_PATTERN.lastIndex = 0;
const match = INTERNAL_MOCK_PATTERN.exec(line);
if (match) {
violations.push({
file: file.replace(process.cwd() + "/", ""),
line: i + 1,
match: match[0],
});
}
}
}
if (violations.length > 0) {
console.warn("\n[mock-policy] Internal module mock violations detected:");
console.warn(
" Rule: Only mock third-party dependencies. See CLAUDE.md Testing Guidelines.\n",
);
for (const v of violations) {
console.warn(` ${v.file}:${v.line}`);
console.warn(` ${v.match}\n`);
}
console.warn(
` Total: ${violations.length} violation(s) in ${new Set(violations.map((v) => v.file)).size} file(s)\n`,
);
}
}
checkMockPolicy();