Files
gridpilot.gg/tests/unit/website/structure/ImportBoundaries.test.ts
2025-12-04 11:54:42 +01:00

81 lines
2.2 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
const websiteRoot = path.resolve(__dirname, '../../../../apps/website');
const forbiddenImportPrefixes = [
"@/lib/demo-data",
"@/lib/inmemory",
"@/lib/social",
"@/lib/email-validation",
"@/lib/membership-data",
"@/lib/registration-data",
"@/lib/team-data",
];
function collectTsFiles(dir: string): string[] {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const files: string[] = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
// Skip Next.js build output if present
if (entry.name === '.next') continue;
files.push(...collectTsFiles(fullPath));
} else if (entry.isFile()) {
if (
entry.name.endsWith('.ts') ||
entry.name.endsWith('.tsx')
) {
files.push(fullPath);
}
}
}
return files;
}
describe('Website import boundaries', () => {
it('does not import forbidden website lib modules directly', () => {
const files = collectTsFiles(websiteRoot);
const violations: { file: string; line: number; content: string }[] = [];
for (const file of files) {
const content = fs.readFileSync(file, 'utf8');
const lines = content.split(/\r?\n/);
lines.forEach((line, index) => {
const trimmed = line.trim();
if (!trimmed.startsWith('import')) return;
for (const prefix of forbiddenImportPrefixes) {
if (trimmed.includes(`"${prefix}`) || trimmed.includes(`'${prefix}`)) {
violations.push({
file,
line: index + 1,
content: line,
});
}
}
});
}
if (violations.length > 0) {
const message =
'Found forbidden imports in apps/website:\n' +
violations
.map(
(v) =>
`- ${v.file}:${v.line} :: ${v.content.trim()}`,
)
.join('\n');
// Fail with detailed message so we can iterate while RED
expect(message).toBe(''); // Intentionally impossible when violations exist
} else {
expect(violations).toEqual([]);
}
});
});