import { describe, it, expect } from 'vitest'; import { readdirSync, readFileSync } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // Belt-and-braces detector for the birpc teardown race named in ADR-012 / #553. // ESLint catches the pattern at save time, CI grep catches it before the test // suite launches, and this in-suite test catches it at every vitest invocation — // the layer hardest to disable or scope around. // // We scan source text rather than parsing AST: fast, no parser dependency, // good enough for the named anti-pattern. The pattern matches // `vi.mock(, async ... { ... await import(...) ... })`. const ASYNC_MOCK_WITH_DYNAMIC_IMPORT = /vi\.mock\([^)]*,\s*async[^{]*\{[\s\S]*?await\s+import\s*\(/; export function hasAsyncMockFactoryWithDynamicImport(source: string): boolean { return ASYNC_MOCK_WITH_DYNAMIC_IMPORT.test(source); } const __dirname = path.dirname(fileURLToPath(import.meta.url)); const SRC_ROOT = path.resolve(__dirname, '..'); function findBrowserSpecs(): string[] { const entries = readdirSync(SRC_ROOT, { recursive: true, withFileTypes: true }); return entries .filter( (e) => e.isFile() && (e.name.endsWith('.svelte.test.ts') || e.name.endsWith('.svelte.spec.ts')) ) .map((e) => path.join(e.parentPath ?? (e as { path: string }).path, e.name)); } describe('scan: hasAsyncMockFactoryWithDynamicImport', () => { it('flags async vi.mock factory with await import in body', () => { const fixture = `vi.mock('$app/stores', async () => { const mod = await import('./__mocks__/navigatingStore'); return { navigating: mod.navigatingStore }; });`; expect(hasAsyncMockFactoryWithDynamicImport(fixture)).toBe(true); }); it('does not flag sync vi.mock factory', () => { const fixture = `vi.mock('$app/state', () => ({ navigating: { type: null } }));`; expect(hasAsyncMockFactoryWithDynamicImport(fixture)).toBe(false); }); it('does not flag async vi.mock factory without dynamic import', () => { const fixture = `vi.mock('foo', async () => { const x = await Promise.resolve(42); return { bar: x }; });`; expect(hasAsyncMockFactoryWithDynamicImport(fixture)).toBe(false); }); it('does not flag dynamic import outside any vi.mock', () => { const fixture = `async function load() { const mod = await import('./something'); return mod.default; }`; expect(hasAsyncMockFactoryWithDynamicImport(fixture)).toBe(false); }); it('flags async factory written as async function expression', () => { const fixture = `vi.mock('foo', async function () { const mod = await import('./bar'); return mod; });`; expect(hasAsyncMockFactoryWithDynamicImport(fixture)).toBe(true); }); }); describe('browser specs: no async vi.mock factory contains await import', () => { it('every src/**/*.svelte.{test,spec}.ts file is clean', () => { const specFiles = findBrowserSpecs(); expect(specFiles.length).toBeGreaterThan(0); const offenders = specFiles.filter((file) => hasAsyncMockFactoryWithDynamicImport(readFileSync(file, 'utf-8')) ); expect(offenders).toEqual([]); }); });