Skip to content

Commit e97eefa

Browse files
atlowChemiMoLow
authored andcommitted
test_runner: execute before hook on test
Execute the before hook for Test as well, and execute it on root before executing any tests. Fixes: #47518 PR-URL: #47586 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent 980bf05 commit e97eefa

4 files changed

Lines changed: 107 additions & 16 deletions

File tree

‎doc/api/test.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,12 +1429,36 @@ Emitted when a test starts.
14291429

14301430
<!-- YAML
14311431
added: v18.0.0
1432+
changes:
1433+
- version: REPLACEME
1434+
pr-url: https://github.com/nodejs/node/pull/47586
1435+
description: The `before` function was added to TestContext.
14321436
-->
14331437

14341438
An instance of `TestContext` is passed to each test function in order to
14351439
interact with the test runner. However, the `TestContext` constructor is not
14361440
exposed as part of the API.
14371441

1442+
### `context.before([fn][, options])`
1443+
1444+
<!-- YAML
1445+
added: REPLACEME
1446+
-->
1447+
1448+
*`fn` {Function|AsyncFunction} The hook function. The first argument
1449+
to this function is a [`TestContext`][] object. If the hook uses callbacks,
1450+
the callback function is passed as the second argument. **Default:** A no-op
1451+
function.
1452+
*`options` {Object} Configuration options for the hook. The following
1453+
properties are supported:
1454+
*`signal` {AbortSignal} Allows aborting an in-progress hook.
1455+
*`timeout` {number} A number of milliseconds the hook will fail after.
1456+
If unspecified, subtests inherit this value from their parent.
1457+
**Default:**`Infinity`.
1458+
1459+
This function is used to create a hook running before
1460+
subtest of the current test.
1461+
14381462
### `context.beforeEach([fn][, options])`
14391463

14401464
<!-- YAML

‎lib/internal/test_runner/test.js‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ class TestContext {
127127
returnsubtest.start();
128128
}
129129

130+
before(fn,options){
131+
this.#test.createHook('before',fn,options);
132+
}
133+
130134
after(fn,options){
131135
this.#test.createHook('after',fn,options);
132136
}
@@ -414,6 +418,9 @@ class Test extends AsyncResource {
414418
validateOneOf(name,'hook name',kHookNames);
415419
// eslint-disable-next-line no-use-before-define
416420
consthook=newTestHook(fn,options);
421+
if(name==='before'){
422+
hook.run=runOnce(hook.run);
423+
}
417424
ArrayPrototypePush(this.hooks[name],hook);
418425
returnhook;
419426
}
@@ -525,6 +532,9 @@ class Test extends AsyncResource {
525532
if(this.parent?.hooks.beforeEach.length>0){
526533
awaitthis.parent.runHook('beforeEach',{ args, ctx });
527534
}
535+
if(this.parent?.hooks.before.length>0){
536+
awaitthis.parent.runHook('before',this.parent.getRunArgs());
537+
}
528538
conststopPromise=stopTest(this.timeout,this.signal);
529539
construnArgs=ArrayPrototypeSlice(args);
530540
ArrayPrototypeUnshift(runArgs,this.fn,ctx);
@@ -561,7 +571,7 @@ class Test extends AsyncResource {
561571
this.pass();
562572
}catch(err){
563573
try{awaitafter();}catch{/* Ignore error. */}
564-
try{awaitafterEach();}catch{/* test is already failing, let's the error */}
574+
try{awaitafterEach();}catch{/* test is already failing, let's ignore the error */}
565575
if(isTestFailureError(err)){
566576
if(err.failureType===kTestTimeoutFailure){
567577
this.#cancel(err);
@@ -793,7 +803,7 @@ class Suite extends Test {
793803

794804
this.pass();
795805
}catch(err){
796-
try{awaitafterEach();}catch{/* test is already failing, let's the error */}
806+
try{awaitafterEach();}catch{/* test is already failing, let's ignore the error */}
797807
if(isTestFailureError(err)){
798808
this.fail(err);
799809
}else{

‎test/fixtures/test-runner/output/hooks.js‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const common = require('../../../common');
44
constassert=require('assert');
55
const{ test, describe, it, before, after, beforeEach, afterEach }=require('node:test');
66

7+
before((t)=>t.diagnostic('before 1 called'));
8+
79
describe('describe hooks',()=>{
810
consttestArr=[];
911
before(function(){
@@ -91,6 +93,7 @@ describe('afterEach throws and test fails', () => {
9193
test('test hooks',async(t)=>{
9294
consttestArr=[];
9395

96+
t.before((t)=>testArr.push('before '+t.name));
9497
t.after(common.mustCall((t)=>testArr.push('after '+t.name)));
9598
t.beforeEach((t)=>testArr.push('beforeEach '+t.name));
9699
t.afterEach((t)=>testArr.push('afterEach '+t.name));
@@ -105,7 +108,7 @@ test('test hooks', async (t) => {
105108
});
106109

107110
assert.deepStrictEqual(testArr,[
108-
'beforeEach 1','1','afterEach 1',
111+
'beforeEach 1','before test hooks','1','afterEach 1',
109112
'beforeEach 2','2','afterEach 2',
110113
'beforeEach nested',
111114
'nested beforeEach nested 1','nested1','nested afterEach nested 1',
@@ -114,6 +117,13 @@ test('test hooks', async (t) => {
114117
]);
115118
});
116119

120+
test('t.before throws',async(t)=>{
121+
t.after(common.mustCall());
122+
t.before(()=>{thrownewError('before');});
123+
awaitt.test('1',()=>{});
124+
awaitt.test('2',()=>{});
125+
});
126+
117127
test('t.beforeEach throws',async(t)=>{
118128
t.after(common.mustCall());
119129
t.beforeEach(()=>{thrownewError('beforeEach');});
@@ -149,3 +159,5 @@ test('t.after() is called if test body throws', (t) => {
149159
});
150160
thrownewError('bye');
151161
});
162+
163+
before((t)=>t.diagnostic('before 2 called'));

‎test/fixtures/test-runner/output/hooks.snapshot‎

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ not ok 2 - before throws
6767
*
6868
*
6969
*
70+
*
7071
...
7172
# Subtest: after throws
7273
# Subtest: 1
@@ -307,6 +308,53 @@ ok 8 - test hooks
307308
---
308309
duration_ms: *
309310
...
311+
# Subtest: t.before throws
312+
# Subtest: 1
313+
not ok 1 - 1
314+
---
315+
duration_ms: *
316+
failureType: 'hookFailed'
317+
error: 'failed running before hook'
318+
code: 'ERR_TEST_FAILURE'
319+
stack: |-
320+
*
321+
*
322+
*
323+
*
324+
*
325+
*
326+
*
327+
*
328+
*
329+
*
330+
...
331+
# Subtest: 2
332+
not ok 2 - 2
333+
---
334+
duration_ms: *
335+
failureType: 'hookFailed'
336+
error: 'failed running before hook'
337+
code: 'ERR_TEST_FAILURE'
338+
stack: |-
339+
*
340+
*
341+
*
342+
*
343+
*
344+
*
345+
*
346+
*
347+
*
348+
*
349+
...
350+
1..2
351+
not ok 9 - t.before throws
352+
---
353+
duration_ms: *
354+
failureType: 'subtestsFailed'
355+
error: '2 subtests failed'
356+
code: 'ERR_TEST_FAILURE'
357+
...
310358
# Subtest: t.beforeEach throws
311359
# Subtest: 1
312360
not ok 1 - 1
@@ -347,7 +395,7 @@ ok 8 - test hooks
347395
*
348396
...
349397
1..2
350-
not ok 9 - t.beforeEach throws
398+
not ok 10 - t.beforeEach throws
351399
---
352400
duration_ms: *
353401
failureType: 'subtestsFailed'
@@ -394,7 +442,7 @@ not ok 9 - t.beforeEach throws
394442
*
395443
...
396444
1..2
397-
not ok 10 - t.afterEach throws
445+
not ok 11 - t.afterEach throws
398446
---
399447
duration_ms: *
400448
failureType: 'subtestsFailed'
@@ -419,15 +467,14 @@ not ok 10 - t.afterEach throws
419467
*
420468
*
421469
*
422-
*
423470
...
424471
# Subtest: 2
425472
ok 2 - 2
426473
---
427474
duration_ms: *
428475
...
429476
1..2
430-
not ok 11 - afterEach when test fails
477+
not ok 12 - afterEach when test fails
431478
---
432479
duration_ms: *
433480
failureType: 'subtestsFailed'
@@ -452,7 +499,6 @@ not ok 11 - afterEach when test fails
452499
*
453500
*
454501
*
455-
*
456502
...
457503
# Subtest: 2
458504
not ok 2 - 2
@@ -474,15 +520,15 @@ not ok 11 - afterEach when test fails
474520
*
475521
...
476522
1..2
477-
not ok 12 - afterEach throws and test fails
523+
not ok 13 - afterEach throws and test fails
478524
---
479525
duration_ms: *
480526
failureType: 'subtestsFailed'
481527
error: '2 subtests failed'
482528
code: 'ERR_TEST_FAILURE'
483529
...
484530
# Subtest: t.after() is called if test body throws
485-
not ok 13 - t.after() is called if test body throws
531+
not ok 14 - t.after() is called if test body throws
486532
---
487533
duration_ms: *
488534
failureType: 'testCodeFailure'
@@ -493,16 +539,15 @@ not ok 13 - t.after() is called if test body throws
493539
*
494540
*
495541
*
496-
*
497-
*
498-
*
499542
...
500543
# - after() called
501-
1..13
502-
# tests 35
544+
1..14
545+
# before 1 called
546+
# before 2 called
547+
# tests 38
503548
# suites 8
504549
# pass 14
505-
# fail 19
550+
# fail 22
506551
# cancelled 2
507552
# skipped 0
508553
# todo 0

0 commit comments

Comments
 (0)