Skip to content

Commit 87ac6cf

Browse files
jakecastelliRafaelGSS
authored andcommitted
test_runner: improve --test-timeout to be per test
Previously `--test-timeout` is set on per test execution, this is obviously a bug as per test execution is hard to be expected, this patch addresses the issue by setting `timeout` from per execution to per test. This patch also fixes a minor issue that `--test-timeout` is not being respected when running without `--test`. PR-URL: #57672Fixes: #57656 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 406b06b commit 87ac6cf

8 files changed

Lines changed: 96 additions & 8 deletions

File tree

‎lib/internal/test_runner/runner.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class FileTest extends Test {
191191
column: 1,
192192
file: resolve(this.name),
193193
};
194+
this.timeout=null;
194195
}
195196

196197
#skipReporting(){

‎lib/internal/test_runner/test.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,12 @@ class Test extends AsyncResource {
608608
if(timeout!=null&&timeout!==Infinity){
609609
validateNumber(timeout,'options.timeout',0,TIMEOUT_MAX);
610610
this.timeout=timeout;
611+
}elseif(timeout==null){
612+
constcliTimeout=this.config.timeout;
613+
if(cliTimeout!=null&&cliTimeout!==Infinity){
614+
validateNumber(cliTimeout,'this.config.timeout',0,TIMEOUT_MAX);
615+
this.timeout=cliTimeout;
616+
}
611617
}
612618

613619
if(skip){
@@ -1394,6 +1400,7 @@ class Suite extends Test {
13941400
reportedType='suite';
13951401
constructor(options){
13961402
super(options);
1403+
this.timeout=null;
13971404

13981405
if(this.config.testNamePatterns!==null&&
13991406
this.config.testSkipPatterns!==null&&

‎lib/internal/test_runner/utils.js‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ function parseCommandLine() {
196196
constsourceMaps=getOptionValue('--enable-source-maps');
197197
constupdateSnapshots=getOptionValue('--test-update-snapshots');
198198
constwatch=getOptionValue('--watch');
199+
consttimeout=getOptionValue('--test-timeout')||Infinity;
199200
constisChildProcess=process.env.NODE_TEST_CONTEXT==='child';
200201
constisChildProcessV8=process.env.NODE_TEST_CONTEXT==='child-v8';
201202
letconcurrency;
@@ -211,7 +212,6 @@ function parseCommandLine() {
211212
letshard;
212213
lettestNamePatterns=mapPatternFlagToRegExArray('--test-name-pattern');
213214
lettestSkipPatterns=mapPatternFlagToRegExArray('--test-skip-pattern');
214-
lettimeout;
215215

216216
if(isChildProcessV8){
217217
kBuiltinReporters.set('v8-serializer','internal/test_runner/reporter/v8-serializer');
@@ -242,7 +242,6 @@ function parseCommandLine() {
242242

243243
if(isTestRunner){
244244
isolation=getOptionValue('--test-isolation');
245-
timeout=getOptionValue('--test-timeout')||Infinity;
246245

247246
if(isolation==='none'){
248247
concurrency=1;
@@ -271,7 +270,6 @@ function parseCommandLine() {
271270
};
272271
}
273272
}else{
274-
timeout=Infinity;
275273
concurrency=1;
276274
consttestNamePatternFlag=getOptionValue('--test-name-pattern');
277275
only=getOptionValue('--test-only');
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Flags: --test-timeout=20
2+
'use strict';
3+
const{ describe, test }=require('node:test');
4+
const{ setTimeout }=require('node:timers/promises');
5+
6+
describe('--test-timeout is set to 20ms',()=>{
7+
test('should timeout after 20ms',async()=>{
8+
awaitsetTimeout(200000,undefined,{ref: false});
9+
});
10+
test('should timeout after 5ms',{timeout: 5},async()=>{
11+
awaitsetTimeout(200000,undefined,{ref: false});
12+
});
13+
14+
test('should not timeout',{timeout: 50000},async()=>{
15+
awaitsetTimeout(1);
16+
});
17+
18+
test('should pass',async()=>{});
19+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
TAP version 13
2+
# Subtest: --test-timeout is set to 20ms
3+
# Subtest: should timeout after 20ms
4+
not ok 1 - should timeout after 20ms
5+
---
6+
duration_ms: *
7+
type: 'test'
8+
location: '/test/fixtures/test-runner/output/test-timeout-flag.js:(LINE):3'
9+
failureType: 'testTimeoutFailure'
10+
error: 'test timed out after 20ms'
11+
code: 'ERR_TEST_FAILURE'
12+
stack: |-
13+
async Promise.all (index 0)
14+
...
15+
# Subtest: should timeout after 5ms
16+
not ok 2 - should timeout after 5ms
17+
---
18+
duration_ms: *
19+
type: 'test'
20+
location: '/test/fixtures/test-runner/output/test-timeout-flag.js:(LINE):3'
21+
failureType: 'testTimeoutFailure'
22+
error: 'test timed out after 5ms'
23+
code: 'ERR_TEST_FAILURE'
24+
...
25+
# Subtest: should not timeout
26+
ok 3 - should not timeout
27+
---
28+
duration_ms: *
29+
type: 'test'
30+
...
31+
# Subtest: should pass
32+
ok 4 - should pass
33+
---
34+
duration_ms: *
35+
type: 'test'
36+
...
37+
1..4
38+
not ok 1 - --test-timeout is set to 20ms
39+
---
40+
duration_ms: *
41+
type: 'suite'
42+
location: '/test/fixtures/test-runner/output/test-timeout-flag.js:(LINE):1'
43+
failureType: 'subtestsFailed'
44+
error: '2 subtests failed'
45+
code: 'ERR_TEST_FAILURE'
46+
...
47+
1..1
48+
# tests 4
49+
# suites 1
50+
# pass 2
51+
# fail 0
52+
# cancelled 2
53+
# skipped 0
54+
# todo 0
55+
# duration_ms *

‎test/parallel/test-runner-filetest-location.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const fixtures = require('../common/fixtures');
44
const{ strictEqual }=require('node:assert');
55
const{ relative }=require('node:path');
66
const{ run }=require('node:test');
7-
constfixture=fixtures.path('test-runner','never_ending_sync.js');
7+
constfixture=fixtures.path('test-runner','index.js');
88
constrelativePath=relative(process.cwd(),fixture);
99
conststream=run({
1010
files: [relativePath],
@@ -13,7 +13,7 @@ const stream = run({
1313

1414
stream.on('test:fail',common.mustCall((result)=>{
1515
strictEqual(result.name,relativePath);
16-
strictEqual(result.details.error.failureType,'testTimeoutFailure');
16+
strictEqual(result.details.error.failureType,'testCodeFailure');
1717
strictEqual(result.line,1);
1818
strictEqual(result.column,1);
1919
strictEqual(result.file,fixture);

‎test/parallel/test-runner-output.mjs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ const tests = [
132132
name: 'test-runner/output/timeout_in_before_each_should_not_affect_further_tests.js',
133133
flags: ['--test-reporter=tap'],
134134
},
135+
{
136+
name: 'test-runner/output/test-timeout-flag.js',
137+
flags: ['--test-reporter=tap'],
138+
},
139+
// --test-timeout should work with or without --test flag
140+
{
141+
name: 'test-runner/output/test-timeout-flag.js',
142+
flags: ['--test-reporter=tap','--test'],
143+
},
135144
{
136145
name: 'test-runner/output/hooks-with-no-global-test.js',
137146
flags: ['--test-reporter=tap'],

‎test/parallel/test-runner-run.mjs‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
7070

7171
it('should support timeout',async()=>{
7272
conststream=run({timeout: 50,files: [
73-
fixtures.path('test-runner','never_ending_sync.js'),
74-
fixtures.path('test-runner','never_ending_async.js'),
73+
fixtures.path('test-runner','timeout-basic.mjs'),
7574
]});
76-
stream.on('test:fail',common.mustCall(2));
75+
stream.on('test:fail',common.mustCall(1));
7776
stream.on('test:pass',common.mustNotCall());
7877
// eslint-disable-next-line no-unused-vars
7978
forawait(const_ofstream);

0 commit comments

Comments
 (0)