|
| 1 | +import * as common from '../common/index.mjs'; |
| 2 | +import { before, describe, it, run } from 'node:test'; |
| 3 | +import assert from 'node:assert'; |
| 4 | +import { spawnSync } from 'node:child_process'; |
| 5 | +import { cp, writeFile } from 'node:fs/promises'; |
| 6 | +import { join, sep } from 'node:path'; |
| 7 | +import tmpdir from '../common/tmpdir.js'; |
| 8 | +import fixtures from '../common/fixtures.js'; |
| 9 | + |
| 10 | +const skipIfNoInspector = { |
| 11 | + skip: !process.features.inspector ? 'inspector disabled' : false, |
| 12 | +}; |
| 13 | + |
| 14 | +tmpdir.refresh(); |
| 15 | + |
| 16 | +async function setupFixtures() { |
| 17 | + const fixtureDir = fixtures.path('test-runner', 'coverage-isolation-none'); |
| 18 | + await cp(fixtureDir, tmpdir.path, { recursive: true }); |
| 19 | +} |
| 20 | + |
| 21 | +describe('run() coverage with isolation: none', skipIfNoInspector, () => { |
| 22 | + before(async () => { |
| 23 | + await setupFixtures(); |
| 24 | + }); |
| 25 | + |
| 26 | + for (const isolation of ['none', 'process']) { |
| 27 | + it(`reports src coverage and excludes test files by default (isolation=${isolation})`, async () => { |
| 28 | + const stream = run({ |
| 29 | + files: [join(tmpdir.path, 'tests', 'foo.test.mjs')], |
| 30 | + coverage: true, |
| 31 | + isolation, |
| 32 | + cwd: tmpdir.path, |
| 33 | + }); |
| 34 | + stream.on('test:fail', common.mustNotCall()); |
| 35 | + |
| 36 | + let summary; |
| 37 | + stream.on('test:coverage', common.mustCall(({ summary: s }) => { |
| 38 | + summary = s; |
| 39 | + })); |
| 40 | + // eslint-disable-next-line no-unused-vars |
| 41 | + for await (const _ of stream); |
| 42 | + |
| 43 | + assert.ok(summary, 'test:coverage event must fire'); |
| 44 | + const paths = summary.files.map((f) => f.path); |
| 45 | + assert.ok( |
| 46 | + paths.length > 0, |
| 47 | + `coverage files must be reported (isolation=${isolation}); got ${JSON.stringify(paths)}`, |
| 48 | + ); |
| 49 | + assert.ok( |
| 50 | + paths.some((p) => p.endsWith(`src${sep}foo.mjs`)), |
| 51 | + `expected src/foo.mjs to be present (isolation=${isolation}); got ${JSON.stringify(paths)}`, |
| 52 | + ); |
| 53 | + assert.ok( |
| 54 | + paths.every((p) => !p.endsWith('foo.test.mjs')), |
| 55 | + `expected foo.test.mjs to be excluded by default (isolation=${isolation}); got ${JSON.stringify(paths)}`, |
| 56 | + ); |
| 57 | + }); |
| 58 | + } |
| 59 | + |
| 60 | + it('is idempotent when --experimental-test-coverage is also passed', async () => { |
| 61 | + const runnerPath = join(tmpdir.path, 'runner.mjs'); |
| 62 | + await writeFile(runnerPath, `\ |
| 63 | +import { run } from 'node:test'; |
| 64 | +import { join } from 'node:path'; |
| 65 | +
|
| 66 | +const stream = run({ |
| 67 | + files: [join(import.meta.dirname, 'tests', 'foo.test.mjs')], |
| 68 | + coverage: true, |
| 69 | + isolation: 'none', |
| 70 | + cwd: import.meta.dirname, |
| 71 | +}); |
| 72 | +stream.on('test:fail', () => process.exit(10)); |
| 73 | +let summary; |
| 74 | +stream.on('test:coverage', (event) => { summary = event.summary; }); |
| 75 | +for await (const _ of stream); |
| 76 | +if (!summary || summary.files.length === 0) process.exit(11); |
| 77 | +const hasSrc = summary.files.some((f) => f.path.endsWith('foo.mjs') && !f.path.endsWith('foo.test.mjs')); |
| 78 | +const hasTest = summary.files.some((f) => f.path.endsWith('foo.test.mjs')); |
| 79 | +if (!hasSrc) process.exit(12); |
| 80 | +if (hasTest) process.exit(13); |
| 81 | +`); |
| 82 | + const result = spawnSync(process.execPath, [ |
| 83 | + '--experimental-test-coverage', |
| 84 | + runnerPath, |
| 85 | + ], { cwd: tmpdir.path }); |
| 86 | + assert.strictEqual( |
| 87 | + result.status, |
| 88 | + 0, |
| 89 | + `exited with ${result.status}\nstderr: ${result.stderr}\nstdout: ${result.stdout}`, |
| 90 | + ); |
| 91 | + }); |
| 92 | +}); |
0 commit comments