29 lines
1.0 KiB
TypeScript
29 lines
1.0 KiB
TypeScript
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);
|
|
});
|
|
});
|