2024-01-25 11:17:31 -05:00
|
|
|
import fs from 'node:fs/promises';
|
|
|
|
import path from 'node:path';
|
2024-08-20 05:25:04 -05:00
|
|
|
import { run } from 'node:test';
|
|
|
|
import { spec } from 'node:test/reporters';
|
2024-01-25 11:17:31 -05:00
|
|
|
import { pathToFileURL } from 'node:url';
|
2024-08-14 05:05:50 -05:00
|
|
|
import { parseArgs } from 'node:util';
|
2024-08-20 05:25:04 -05:00
|
|
|
import glob from 'fast-glob';
|
2024-01-12 02:53:00 -05:00
|
|
|
|
|
|
|
const isCI = !!process.env.CI;
|
2024-04-10 09:38:17 -05:00
|
|
|
const defaultTimeout = isCI ? 1400000 : 600000;
|
2024-01-12 02:53:00 -05:00
|
|
|
|
|
|
|
export default async function test() {
|
2024-08-14 05:05:50 -05:00
|
|
|
const args = parseArgs({
|
|
|
|
allowPositionals: true,
|
|
|
|
options: {
|
|
|
|
// aka --test-name-pattern: https://nodejs.org/api/test.html#filtering-tests-by-name
|
|
|
|
match: { type: 'string', alias: 'm' },
|
|
|
|
// aka --test-only: https://nodejs.org/api/test.html#only-tests
|
|
|
|
only: { type: 'boolean', alias: 'o' },
|
|
|
|
// aka --test-concurrency: https://nodejs.org/api/test.html#test-runner-execution-model
|
|
|
|
parallel: { type: 'boolean', alias: 'p' },
|
|
|
|
// experimental: https://nodejs.org/api/test.html#watch-mode
|
|
|
|
watch: { type: 'boolean', alias: 'w' },
|
|
|
|
// Test timeout in milliseconds (default: 30000ms)
|
|
|
|
timeout: { type: 'string', alias: 't' },
|
|
|
|
// Test setup file
|
|
|
|
setup: { type: 'string', alias: 's' },
|
2024-10-15 02:34:42 -05:00
|
|
|
// Test teardown file
|
|
|
|
teardown: { type: 'string' },
|
2024-08-14 05:05:50 -05:00
|
|
|
},
|
2024-01-12 02:53:00 -05:00
|
|
|
});
|
|
|
|
|
2024-08-14 05:05:50 -05:00
|
|
|
const pattern = args.positionals[1];
|
2024-01-12 02:53:00 -05:00
|
|
|
if (!pattern) throw new Error('Missing test glob pattern');
|
|
|
|
|
2024-08-20 05:25:04 -05:00
|
|
|
const files = await glob(pattern, {
|
|
|
|
filesOnly: true,
|
|
|
|
absolute: true,
|
|
|
|
ignore: ['**/node_modules/**'],
|
|
|
|
});
|
2024-01-12 02:53:00 -05:00
|
|
|
|
|
|
|
// For some reason, the `only` option does not work and we need to explicitly set the CLI flag instead.
|
|
|
|
// Node.js requires opt-in to run .only tests :(
|
|
|
|
// https://nodejs.org/api/test.html#only-tests
|
2024-08-14 05:05:50 -05:00
|
|
|
if (args.values.only) {
|
2024-01-12 02:53:00 -05:00
|
|
|
process.env.NODE_OPTIONS ??= '';
|
|
|
|
process.env.NODE_OPTIONS += ' --test-only';
|
|
|
|
}
|
|
|
|
|
2024-08-14 05:05:50 -05:00
|
|
|
if (!args.values.parallel) {
|
2024-01-25 11:17:31 -05:00
|
|
|
// If not parallel, we create a temporary file that imports all the test files
|
|
|
|
// so that it all runs in a single process.
|
|
|
|
const tempTestFile = path.resolve('./node_modules/.astro/test.mjs');
|
|
|
|
await fs.mkdir(path.dirname(tempTestFile), { recursive: true });
|
|
|
|
await fs.writeFile(
|
|
|
|
tempTestFile,
|
2024-08-20 05:25:04 -05:00
|
|
|
files.map((f) => `import ${JSON.stringify(pathToFileURL(f).toString())};`).join('\n'),
|
2024-01-25 11:17:31 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
files.length = 0;
|
|
|
|
files.push(tempTestFile);
|
|
|
|
}
|
|
|
|
|
2024-10-15 02:34:42 -05:00
|
|
|
const teardownModule = args.values.teardown
|
|
|
|
? await import(pathToFileURL(path.resolve(args.values.teardown)).toString())
|
|
|
|
: undefined;
|
|
|
|
|
2024-01-12 02:53:00 -05:00
|
|
|
// https://nodejs.org/api/test.html#runoptions
|
|
|
|
run({
|
|
|
|
files,
|
2024-08-14 05:05:50 -05:00
|
|
|
testNamePatterns: args.values.match,
|
|
|
|
concurrency: args.values.parallel,
|
|
|
|
only: args.values.only,
|
|
|
|
setup: args.values.setup,
|
|
|
|
watch: args.values.watch,
|
|
|
|
timeout: args.values.timeout ? Number(args.values.timeout) : defaultTimeout, // Node.js defaults to Infinity, so set better fallback
|
2024-01-12 02:53:00 -05:00
|
|
|
})
|
2024-02-01 10:47:13 -05:00
|
|
|
.on('test:fail', () => {
|
|
|
|
// For some reason, a test fail using the JS API does not set an exit code of 1,
|
|
|
|
// so we set it here manually
|
|
|
|
process.exitCode = 1;
|
|
|
|
})
|
2024-10-15 02:34:42 -05:00
|
|
|
.on('end', () => {
|
|
|
|
const testPassed = process.exitCode === 0 || process.exitCode === undefined;
|
|
|
|
teardownModule?.default(testPassed);
|
|
|
|
})
|
2024-01-12 02:53:00 -05:00
|
|
|
.pipe(new spec())
|
|
|
|
.pipe(process.stdout);
|
|
|
|
}
|