Files
node/test/parallel/test-runner-coverage-isolation-none-api.mjs
sangwook c9dbb86683 inspector: expose precise coverage start to JS runtime
Add a `startCoverage` method on the `profiler` internal binding so
that V8 precise coverage can be enabled after bootstrap. The method
is idempotent against the existing bootstrap path (which creates a
V8CoverageConnection when NODE_V8_COVERAGE or
--experimental-test-coverage is set) and a no-op when the inspector
is unavailable, e.g. in the parent process of
`--test --test-isolation=process` where workers handle coverage and
Environment::should_create_inspector() returns false.

Refs: https://github.com/nodejs/node/issues/60023
Signed-off-by: sangwook <rewq5991@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63079
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-05-23 17:02:02 +00:00

72 lines
2.4 KiB
JavaScript

import * as common from '../common/index.mjs';
import { before, describe, it, run } from 'node:test';
import assert from 'node:assert';
import { spawnSync } from 'node:child_process';
import { cp } from 'node:fs/promises';
import { join, sep } from 'node:path';
import tmpdir from '../common/tmpdir.js';
import fixtures from '../common/fixtures.js';
const skipIfNoInspector = {
skip: !process.features.inspector ? 'inspector disabled' : false,
};
tmpdir.refresh();
async function setupFixtures() {
const fixtureDir = fixtures.path('test-runner', 'coverage-isolation-none');
await cp(fixtureDir, tmpdir.path, { recursive: true });
}
describe('run() coverage with isolation: none', skipIfNoInspector, () => {
before(async () => {
await setupFixtures();
});
for (const isolation of ['none', 'process']) {
it(`reports src coverage and excludes test files by default (isolation=${isolation})`, async () => {
const stream = run({
files: [join(tmpdir.path, 'tests', 'foo.test.mjs')],
coverage: true,
isolation,
cwd: tmpdir.path,
});
stream.on('test:fail', common.mustNotCall());
let summary;
stream.on('test:coverage', common.mustCall(({ summary: s }) => {
summary = s;
}));
// eslint-disable-next-line no-unused-vars
for await (const _ of stream);
assert.ok(summary, 'test:coverage event must fire');
const paths = summary.files.map((f) => f.path);
assert.ok(
paths.length > 0,
`coverage files must be reported (isolation=${isolation}); got ${JSON.stringify(paths)}`,
);
assert.ok(
paths.some((p) => p.endsWith(`src${sep}foo.mjs`)),
`expected src/foo.mjs to be present (isolation=${isolation}); got ${JSON.stringify(paths)}`,
);
assert.ok(
paths.every((p) => !p.endsWith('foo.test.mjs')),
`expected foo.test.mjs to be excluded by default (isolation=${isolation}); got ${JSON.stringify(paths)}`,
);
});
}
it('is idempotent when --experimental-test-coverage is also passed', async () => {
const result = spawnSync(process.execPath, [
'--experimental-test-coverage',
join(tmpdir.path, 'runner.mjs'),
], { cwd: tmpdir.path });
assert.strictEqual(
result.status,
0,
`exited with ${result.status}\nstderr: ${result.stderr}\nstdout: ${result.stdout}`,
);
});
});