import { readdirSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; const srcDir = fileURLToPath(new URL('.', import.meta.url)); function moduleFiles(dir: string): string[] { return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? moduleFiles(join(dir, entry.name)) : entry.name.endsWith('.module.ts') ? [join(dir, entry.name)] : [], ); } describe('ScheduleModule.forRoot single registration', () => { // Regression guard (v0.21.7): each forRoot() call creates its own ScheduleExplorer that scans all providers, so a second call made every @Cron/@Interval job fire twice. it('appears exactly once across all src/**/*.module.ts', () => { const hits = moduleFiles(srcDir).flatMap((file) => ( readFileSync(file, 'utf8').match(/ScheduleModule\.forRoot\(/g) ?? [] ).map(() => file.slice(srcDir.length)), ); expect(hits).toHaveLength(1); }); });