Skip to content

Commit

Permalink
test: wait for stream finish when --test-force-exit
Browse files Browse the repository at this point in the history
  • Loading branch information
avivkeller committed Sep 15, 2024
1 parent a65105e commit 016dddf
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 6 deletions.
6 changes: 5 additions & 1 deletion lib/internal/test_runner/test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';
const {
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypePushApply,
ArrayPrototypeReduce,
Expand All @@ -20,6 +21,7 @@ const {
RegExpPrototypeExec,
SafeMap,
SafePromiseAll,
SafePromiseAllReturnVoid,
SafePromisePrototypeFinally,
SafePromiseRace,
SafeSet,
Expand Down Expand Up @@ -64,6 +66,7 @@ const { setTimeout } = require('timers');
const { TIMEOUT_MAX } = require('internal/timers');
const { fileURLToPath } = require('internal/url');
const { availableParallelism } = require('os');
const { finished } = require('stream/promises');
const { bigint: hrtime } = process.hrtime;
const kCallbackAndPromisePresent = 'callbackAndPromisePresent';
const kCancelledByParent = 'cancelledByParent';
Expand Down Expand Up @@ -963,7 +966,8 @@ class Test extends AsyncResource {
// any remaining ref'ed handles, then do that now. It is theoretically
// possible that a ref'ed handle could asynchronously create more tests,
// but the user opted into this behavior.
this.reporter.once('close', () => {
this.reporter.once('close', async () => {
await SafePromiseAllReturnVoid(ArrayPrototypeMap(this.reporter.streams, (stream) => finished(stream)));
process.exit();
});
this.harness.teardown();
Expand Down
1 change: 1 addition & 0 deletions lib/internal/test_runner/tests_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class TestsStream extends Readable {
objectMode: true,
highWaterMark: NumberMAX_SAFE_INTEGER,
});
this.streams = [];
this.#buffer = [];
this.#canPush = true;
}
Expand Down
4 changes: 3 additions & 1 deletion lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,9 @@ function parseCommandLine() {

for (let i = 0; i < reportersMap.length; i++) {
const { reporter, destination } = reportersMap[i];
compose(rootReporter, reporter).pipe(destination);
const stream = compose(rootReporter, reporter);
stream.pipe(destination);
ArrayPrototypePush(rootReporter.streams, stream);
}
});

Expand Down
24 changes: 24 additions & 0 deletions test-runner-force-exit-dot.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
X.X

Failed tests:

βœ– Failing test (1.601959ms)
AssertionError [ERR_ASSERTION]: Failed
*
*
*
*
*
*
at new Promise (<anonymous>)
*
*
at Array.map (<anonymous>) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: undefined,
expected: undefined,
operator: 'fail'
}
βœ– Suite (3.340613ms)
'1 subtest failed'
41 changes: 41 additions & 0 deletions test-runner-force-exit-junit.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite name="Suite" time="0.003332" disabled="0" errors="0" tests="2" failures="1" skipped="0" hostname="Jedi8-KALI">
<testcase name="Failing test" time="0.001619" classname="test" failure="Failed">
<failure type="testCodeFailure" message="Failed">
Error [ERR_TEST_FAILURE]: Failed
at new Promise (&lt;anonymous>)
at Array.map (&lt;anonymous>) {
code: 'ERR_TEST_FAILURE',
failureType: 'testCodeFailure',
cause: AssertionError [ERR_ASSERTION]: Failed
*
*
*
*
*
*
at new Promise (&lt;anonymous>)
*
*
at Array.map (&lt;anonymous>) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: undefined,
expected: undefined,
operator: 'fail'
}
}
</failure>
</testcase>
<testcase name="Passing test" time="0.000220" classname="test"/>
</testsuite>
<!-- tests 2 -->
<!-- suites 1 -->
<!-- pass 1 -->
<!-- fail 1 -->
<!-- cancelled 0 -->
<!-- skipped 0 -->
<!-- todo 0 -->
<!-- duration_ms * -->
</testsuites>
52 changes: 52 additions & 0 deletions test-runner-force-exit-spec.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
β–Ά Suite
βœ– Failing test (2.788262ms)
AssertionError [ERR_ASSERTION]: Failed
*
*
*
*
*
*
at new Promise (<anonymous>)
*
*
at Array.map (<anonymous>) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: undefined,
expected: undefined,
operator: 'fail'
}

βœ” Passing test (0.261558ms)
β–Ά Suite (4.670433ms)
β„Ή tests 2
β„Ή suites 1
β„Ή pass 1
β„Ή fail 1
β„Ή cancelled 0
β„Ή skipped 0
β„Ή todo 0
β„Ή duration_ms *

βœ– failing tests:

*
βœ– Failing test (2.788262ms)
AssertionError [ERR_ASSERTION]: Failed
*
*
*
*
*
*
at new Promise (<anonymous>)
*
*
at Array.map (<anonymous>) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: undefined,
expected: undefined,
operator: 'fail'
}
48 changes: 48 additions & 0 deletions test-runner-force-exit-tap.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
TAP version 13
# Subtest: Suite
# Subtest: Failing test
not ok 1 - Failing test
---
duration_ms: *
location: '/test/fixtures/test-runner/output/test-runner-force-exit.js:(LINE):5'
failureType: 'testCodeFailure'
error: 'Failed'
code: 'ERR_ASSERTION'
name: 'AssertionError'
operator: 'fail'
stack: |-
*
*
*
*
*
*
new Promise (<anonymous>)
*
*
Array.map (<anonymous>)
...
# Subtest: Passing test
ok 2 - Passing test
---
duration_ms: *
...
1..2
not ok 1 - Suite
---
duration_ms: *
type: 'suite'
location: '/test/fixtures/test-runner/output/test-runner-force-exit.js:(LINE):1'
failureType: 'subtestsFailed'
error: '1 subtest failed'
code: 'ERR_TEST_FAILURE'
...
1..1
# tests 2
# suites 1
# pass 1
# fail 1
# cancelled 0
# skipped 0
# todo 0
# duration_ms *
4 changes: 2 additions & 2 deletions test/common/assertSnapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async function assertSnapshot(actual, filename = process.argv[1]) {
* @param {boolean} [options.tty] - whether to spawn the process in a pseudo-tty
* @returns {Promise<void>}
*/
async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...options } = {}) {
async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...options } = {}, snapshot = filename) {
if (tty && common.isWindows) {
test({ skip: 'Skipping pseudo-tty tests, as pseudo terminals are not available on Windows.' });
return;
Expand All @@ -88,7 +88,7 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...
[path.join(__dirname, '../..', 'tools/pseudo-tty.py'), process.execPath, ...flags, filename] :
[...flags, filename];
const { stdout, stderr } = await common.spawnPromisified(executable, args, options);
await assertSnapshot(transform(`${stdout}${stderr}`), filename);
await assertSnapshot(transform(`${stdout}${stderr}`), snapshot);
}

module.exports = {
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/test-runner/output/test-runner-force-exit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { describe, test } = require('node:test');
const assert = require('node:assert');

describe('Suite', () => {
test('Failing test', () => {
assert.fail()
})

test('Passing test', () => {
assert.ok(true)
})
});
24 changes: 22 additions & 2 deletions test/parallel/test-runner-output.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,26 @@ const tests = [
name: 'test-runner/output/test-runner-plan.js',
flags: ['--test-reporter=tap'],
},
{
name: 'test-runner/output/test-runner-force-exit.js',
flags: ['--test-reporter=dot'],
snapshotPath: 'test-runner-force-exit-dot'
},
{
name: 'test-runner/output/test-runner-force-exit.js',
flags: ['--test-reporter=junit'],
snapshotPath: 'test-runner-force-exit-junit'
},
{
name: 'test-runner/output/test-runner-force-exit.js',
flags: ['--test-reporter=spec'],
snapshotPath: 'test-runner-force-exit-spec'
},
{
name: 'test-runner/output/test-runner-force-exit.js',
flags: ['--test-reporter=tap'],
snapshotPath: 'test-runner-force-exit-tap'
},
process.features.inspector ? {
name: 'test-runner/output/coverage_failure.js',
flags: ['--test-reporter=tap'],
Expand Down Expand Up @@ -261,10 +281,10 @@ const tests = [
} : false,
]
.filter(Boolean)
.map(({ flags, name, tty, transform }) => ({
.map(({ flags, name, tty, transform, snapshotPath }) => ({
name,
fn: common.mustCall(async () => {
await snapshot.spawnAndAssert(fixtures.path(name), transform ?? defaultTransform, { tty, flags });
await snapshot.spawnAndAssert(fixtures.path(name), transform ?? defaultTransform, { tty, flags }, snapshotPath);

Check failure on line 287 in test/parallel/test-runner-output.mjs

View workflow job for this annotation

GitHub Actions / test-macOS

--- stdout --- β–Ά test runner output βœ” test-runner/output/abort.js (1525.233625ms) βœ” test-runner/output/abort-runs-after-hook.js (514.162958ms) ::debug::starting to run test runner output ::debug::starting to run test-runner/output/abort.js ::debug::completed running test-runner/output/abort.js ::debug::starting to run test-runner/output/abort-runs-after-hook.js ::debug::completed running test-runner/output/abort-runs-after-hook.js βœ” test-runner/output/abort_suite.js (1627.887459ms) βœ” test-runner/output/abort_hooks.js (1500.103083ms) ::debug::starting to run test-runner/output/abort_suite.js ::debug::completed running test-runner/output/abort_suite.js ::debug::starting to run test-runner/output/abort_hooks.js ::debug::completed running test-runner/output/abort_hooks.js βœ” test-runner/output/describe_it.js (1939.230625ms) βœ” test-runner/output/describe_nested.js (1603.365875ms) βœ” test-runner/output/eval_dot.js (1212.63075ms) βœ” test-runner/output/eval_spec.js (1201.047125ms) βœ” test-runner/output/eval_tap.js (1687.960208ms) βœ” test-runner/output/filtered-suite-delayed-build.js (1345.607583ms) βœ” test-runner/output/filtered-suite-order.mjs (1455.584917ms) ::debug::starting to run test-runner/output/describe_it.js ::debug::completed running test-runner/output/describe_it.js ::debug::starting to run test-runner/output/describe_nested.js ::debug::completed running test-runner/output/describe_nested.js ::debug::starting to run test-runner/output/eval_dot.js ::debug::completed running test-runner/output/eval_dot.js ::debug::starting to run test-runner/output/eval_spec.js ::debug::completed running test-runner/output/eval_spec.js ::debug::starting to run test-runner/output/eval_tap.js ::debug::completed running test-runner/output/eval_tap.js ::debug::starting to run test-runner/output/filtered-suite-delayed-build.js ::debug::completed running test-runner/output/filtered-suite-delayed-build.js ::debug::starting to run test-runner/output/filtered-suite-order.mjs ::debug::completed running test-runner/output/filtered-suite-order.mjs ::debug::starting to run test-runner/output/filtered-suite-throws.js βœ” test-runner/output/filtered-suite-throws.js (1404.682958ms) βœ” test-runner/output/hooks.js (1881.180875ms) ::debug::completed running test-runner/output/filtered-suite-throws.js ::debug::starting to run test-runner/output/hooks.js ::debug::completed running test-runner/output/hooks.js βœ” test-runner/output/hooks_spec_reporter.js (2178.85025ms) βœ” test-runner/output/skip-each-hooks.js (1110.559541ms) βœ” test-runner/output/suite-skip-hooks.js (1390.428625ms) ::debug::starting to run test-runner/output/hooks_spec_reporter.js ::debug::completed running test-runner/output/hooks_spec_reporter.js ::debug::starting to run test-runner/output/skip-each-hooks.js ::debug::completed running test-runner/output/skip-each-hooks.js ::debug::starting to run test-runner/output/suite-skip-hooks.js ::debug::completed running test-runner/output/suite-skip-hooks.js βœ” test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js (2268.318166ms) βœ” test-runner/output/hooks-with-no-global-test.js (1216.279583ms) βœ” test-runner/output/global-hooks-with-no-tests.js (1249.406167ms) βœ” test-runner/output/before-and-after-each-too-many-listeners.js (930.864ms) βœ” test-runner/output/before-and-after-each-with-timeout-too-many-listeners.js (1232.124375ms) βœ” test-runner/output/force_exit.js (1269.453167ms) βœ” test-runner/output/global_after_should_fail_the_test.js (1300.920292ms) ::debug::starting to run test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js ::debug::completed running test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js ::debug::starting to run test-runner/output/hooks-with-no-global-test.js ::debug::completed running test-runner/output/hooks-with-no-global-test.js ::debug::starting to run test-runner/output/global-hooks-with-no-tests.js ::debug::completed running test-runner/output/global-hooks-with-no-tests.js ::debug::starting to run test-runner/output/befor

Check failure on line 287 in test/parallel/test-runner-output.mjs

View workflow job for this annotation

GitHub Actions / test-linux

--- stdout --- β–Ά test runner output βœ” test-runner/output/abort.js (1823.982022ms) βœ” test-runner/output/abort-runs-after-hook.js (1803.84202ms) βœ” test-runner/output/abort_suite.js (1801.856254ms) βœ” test-runner/output/abort_hooks.js (1799.183702ms) ::debug::starting to run test runner output ::debug::starting to run test-runner/output/abort.js ::debug::completed running test-runner/output/abort.js ::debug::starting to run test-runner/output/abort-runs-after-hook.js ::debug::completed running test-runner/output/abort-runs-after-hook.js ::debug::starting to run test-runner/output/abort_suite.js ::debug::completed running test-runner/output/abort_suite.js ::debug::starting to run test-runner/output/abort_hooks.js ::debug::completed running test-runner/output/abort_hooks.js βœ” test-runner/output/describe_it.js (1847.120033ms) βœ” test-runner/output/describe_nested.js (1785.7012ms) βœ” test-runner/output/eval_dot.js (1776.925166ms) βœ” test-runner/output/eval_spec.js (1766.890305ms) βœ” test-runner/output/eval_tap.js (1759.810119ms) βœ” test-runner/output/filtered-suite-delayed-build.js (1751.521155ms) βœ” test-runner/output/filtered-suite-order.mjs (1740.171867ms) ::debug::starting to run test-runner/output/describe_it.js ::debug::completed running test-runner/output/describe_it.js ::debug::starting to run test-runner/output/describe_nested.js ::debug::completed running test-runner/output/describe_nested.js ::debug::starting to run test-runner/output/eval_dot.js ::debug::completed running test-runner/output/eval_dot.js ::debug::starting to run test-runner/output/eval_spec.js ::debug::completed running test-runner/output/eval_spec.js ::debug::starting to run test-runner/output/eval_tap.js ::debug::completed running test-runner/output/eval_tap.js ::debug::starting to run test-runner/output/filtered-suite-delayed-build.js ::debug::completed running test-runner/output/filtered-suite-delayed-build.js ::debug::starting to run test-runner/output/filtered-suite-order.mjs ::debug::completed running test-runner/output/filtered-suite-order.mjs ::debug::starting to run test-runner/output/filtered-suite-throws.js βœ” test-runner/output/filtered-suite-throws.js (1727.470511ms) βœ” test-runner/output/hooks.js (1772.438471ms) ::debug::completed running test-runner/output/filtered-suite-throws.js ::debug::starting to run test-runner/output/hooks.js ::debug::completed running test-runner/output/hooks.js βœ” test-runner/output/hooks_spec_reporter.js (1825.796851ms) βœ” test-runner/output/skip-each-hooks.js (1686.254973ms) βœ” test-runner/output/suite-skip-hooks.js (1670.268173ms) βœ” test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js (1749.792801ms) βœ” test-runner/output/hooks-with-no-global-test.js (1615.906268ms) βœ” test-runner/output/global-hooks-with-no-tests.js (1590.156864ms) βœ” test-runner/output/before-and-after-each-too-many-listeners.js (1574.934486ms) ::debug::starting to run test-runner/output/hooks_spec_reporter.js ::debug::completed running test-runner/output/hooks_spec_reporter.js ::debug::starting to run test-runner/output/skip-each-hooks.js ::debug::completed running test-runner/output/skip-each-hooks.js ::debug::starting to run test-runner/output/suite-skip-hooks.js ::debug::completed running test-runner/output/suite-skip-hooks.js ::debug::starting to run test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js ::debug::completed running test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js ::debug::starting to run test-runner/output/hooks-with-no-global-test.js ::debug::completed running test-runner/output/hooks-with-no-global-test.js ::debug::starting to run test-runner/output/global-hooks-with-no-tests.js ::debug::completed running test-runner/output/global-hooks-with-no-tests.js ::debug::starting to run test-runner/output/before-and-after-each-too-many-listeners.js ::debug::completed running test-runner/output/before-and-after-each-too-many-listeners.js ::debug::starting to run test-runner/output/before-and-after-each-with-timeout-too-many-list
}),
}));

Expand Down

0 comments on commit 016dddf

Please sign in to comment.