| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 19e8ce1 commit 8c989ec
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -533,6 +533,8 @@ function setupCoverage(options) { | |||
| 533 | 533 | return null; | |
| 534 | 534 | } | |
| 535 | 535 | ||
| 536 | + internalBinding('profiler').startCoverage(); | ||
| 537 | + | ||
| 536 | 538 | // Ensure that NODE_V8_COVERAGE is set so that coverage can propagate to | |
| 537 | 539 | // child processes. | |
| 538 | 540 | process.env.NODE_V8_COVERAGE = coverageDirectory; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -839,6 +839,8 @@ function run(options = kEmptyObject) { | |||
| 839 | 839 | coverageExcludeGlobs = [coverageExcludeGlobs]; | |
| 840 | 840 | } | |
| 841 | 841 | validateStringArray(coverageExcludeGlobs, 'options.coverageExcludeGlobs'); | |
| 842 | + } else if (coverage) { | ||
| 843 | + coverageExcludeGlobs = [kDefaultPattern]; | ||
| 842 | 844 | } | |
| 843 | 845 | if (coverageIncludeGlobs != null) { | |
| 844 | 846 | if (!ArrayIsArray(coverageIncludeGlobs)) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -548,6 +548,30 @@ static void SetSourceMapCacheGetter(const FunctionCallbackInfo<Value>& args) { | |||
| 548 | 548 | env->set_source_map_cache_getter(args[0].As<Function>()); | |
| 549 | 549 | } | |
| 550 | 550 | ||
| 551 | + static void StartCoverage(const FunctionCallbackInfo<Value>& args) { | ||
| 552 | + Environment* env = Environment::GetCurrent(args); | ||
| 553 | + | ||
| 554 | + Debug(env, | ||
| 555 | + DebugCategory::INSPECTOR_PROFILER, | ||
| 556 | + "StartCoverage, connection %s nullptr\n", | ||
| 557 | + env->coverage_connection() == nullptr ? "==" : "!="); | ||
| 558 | + | ||
| 559 | + if (env->coverage_connection() != nullptr) { | ||
| 560 | + return; | ||
| 561 | + } | ||
| 562 | + | ||
| 563 | + // The parent of `--test --test-isolation=process` intentionally has no | ||
| 564 | + // inspector (see Environment::should_create_inspector); workers handle | ||
| 565 | + // coverage themselves. Without an inspector, V8CoverageConnection would | ||
| 566 | + // get a null session and crash on the first DispatchMessage. | ||
| 567 | + if (!env->should_create_inspector()) { | ||
| 568 | + return; | ||
| 569 | + } | ||
| 570 | + | ||
| 571 | + env->set_coverage_connection(std::make_unique<V8CoverageConnection>(env)); | ||
| 572 | + env->coverage_connection()->Start(); | ||
| 573 | + } | ||
| 574 | + | ||
| 551 | 575 | static void TakeCoverage(const FunctionCallbackInfo<Value>& args) { | |
| 552 | 576 | Environment* env = Environment::GetCurrent(args); | |
| 553 | 577 | V8CoverageConnection* connection = env->coverage_connection(); | |
@@ -601,6 +625,7 @@ static void Initialize(Local<Object> target, | |||
| 601 | 625 | SetMethod(context, target, "setCoverageDirectory", SetCoverageDirectory); | |
| 602 | 626 | SetMethod( | |
| 603 | 627 | context, target, "setSourceMapCacheGetter", SetSourceMapCacheGetter); | |
| 628 | + SetMethod(context, target, "startCoverage", StartCoverage); | ||
| 604 | 629 | SetMethod(context, target, "takeCoverage", TakeCoverage); | |
| 605 | 630 | SetMethod(context, target, "stopCoverage", StopCoverage); | |
| 606 | 631 | SetMethod(context, target, "endCoverage", EndCoverage); | |
@@ -609,6 +634,7 @@ static void Initialize(Local<Object> target, | |||
| 609 | 634 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |
| 610 | 635 | registry->Register(SetCoverageDirectory); | |
| 611 | 636 | registry->Register(SetSourceMapCacheGetter); | |
| 637 | + registry->Register(StartCoverage); | ||
| 612 | 638 | registry->Register(TakeCoverage); | |
| 613 | 639 | registry->Register(StopCoverage); | |
| 614 | 640 | registry->Register(EndCoverage); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + import { run } from 'node:test'; | ||
| 2 | + import { join } from 'node:path'; | ||
| 3 | + | ||
| 4 | + const stream = run({ | ||
| 5 | + files: [join(import.meta.dirname, 'tests', 'foo.test.mjs')], | ||
| 6 | + coverage: true, | ||
| 7 | + isolation: 'none', | ||
| 8 | + cwd: import.meta.dirname, | ||
| 9 | + }); | ||
| 10 | + stream.on('test:fail', () => process.exit(10)); | ||
| 11 | + let summary; | ||
| 12 | + stream.on('test:coverage', (event) => { summary = event.summary; }); | ||
| 13 | + for await (const _ of stream); | ||
| 14 | + if (!summary || summary.files.length === 0) process.exit(11); | ||
| 15 | + const hasSrc = summary.files.some((f) => f.path.endsWith('foo.mjs') && !f.path.endsWith('foo.test.mjs')); | ||
| 16 | + const hasTest = summary.files.some((f) => f.path.endsWith('foo.test.mjs')); | ||
| 17 | + if (!hasSrc) process.exit(12); | ||
| 18 | + if (hasTest) process.exit(13); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,11 @@ | |||
| 1 | + export function add(a, b) { | ||
| 2 | + return a + b; | ||
| 3 | + } | ||
| 4 | + | ||
| 5 | + export function sub(a, b) { | ||
| 6 | + return a - b; | ||
| 7 | + } | ||
| 8 | + | ||
| 9 | + export function unused() { | ||
| 10 | + return 'unused'; | ||
| 11 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,11 @@ | |||
| 1 | + import test from 'node:test'; | ||
| 2 | + import assert from 'node:assert'; | ||
| 3 | + import { add, sub } from '../src/foo.mjs'; | ||
| 4 | + | ||
| 5 | + test('add', () => { | ||
| 6 | + assert.strictEqual(add(2, 3), 5); | ||
| 7 | + }); | ||
| 8 | + | ||
| 9 | + test('sub', () => { | ||
| 10 | + assert.strictEqual(sub(5, 3), 2); | ||
| 11 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,71 @@ | |||
| 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 } 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 result = spawnSync(process.execPath, [ | ||
| 62 | + '--experimental-test-coverage', | ||
| 63 | + join(tmpdir.path, 'runner.mjs'), | ||
| 64 | + ], { cwd: tmpdir.path }); | ||
| 65 | + assert.strictEqual( | ||
| 66 | + result.status, | ||
| 67 | + 0, | ||
| 68 | + `exited with ${result.status}\nstderr: ${result.stderr}\nstdout: ${result.stdout}`, | ||
| 69 | + ); | ||
| 70 | + }); | ||
| 71 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -123,6 +123,7 @@ describe('require(\'node:test\').run coverage settings', { concurrency: true }, | |||
| 123 | 123 | const stream = run({ | |
| 124 | 124 | files, | |
| 125 | 125 | coverage: true, | |
| 126 | + coverageExcludeGlobs: '!test/**', | ||
| 126 | 127 | coverageIncludeGlobs: ['test/fixtures/test-runner/coverage.js', 'test/*/v8-coverage/throw.js'], | |
| 127 | 128 | }); | |
| 128 | 129 | stream.on('test:fail', common.mustNotCall()); | |
@@ -157,7 +158,14 @@ describe('require(\'node:test\').run coverage settings', { concurrency: true }, | |||
| 157 | 158 | const thresholdErrors = []; | |
| 158 | 159 | const originalExitCode = process.exitCode; | |
| 159 | 160 | assert.notStrictEqual(originalExitCode, 1); | |
| 160 | - const stream = run({ files, coverage: true, lineCoverage: 99, branchCoverage: 99, functionCoverage: 99 }); | ||
| 161 | + const stream = run({ | ||
| 162 | + files, | ||
| 163 | + coverage: true, | ||
| 164 | + coverageExcludeGlobs: '!test/**', | ||
| 165 | + lineCoverage: 99, | ||
| 166 | + branchCoverage: 99, | ||
| 167 | + functionCoverage: 99, | ||
| 168 | + }); | ||
| 161 | 169 | stream.on('test:fail', common.mustNotCall()); | |
| 162 | 170 | stream.on('test:pass', common.mustCall(1)); | |
| 163 | 171 | stream.on('test:diagnostic', ({ message }) => { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments