Skip to content

Commit f2815af

Browse files
MrJithilMoLow
authored andcommitted
fix: fix afterEach not running on test failures
PR-URL: nodejs/node#45204 Fixes: nodejs/node#45192 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> (cherry picked from commit 3759935ee29d8042d917d3ceaa768521c14413ff)
1 parent 08269c5 commit f2815af

File tree

7 files changed

+227
-28
lines changed

7 files changed

+227
-28
lines changed

lib/internal/per_context/primordials.js

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ exports.StringPrototypeSlice = (str, ...args) => str.slice(...args)
5959
exports.StringPrototypeSplit = (str, search, limit) => str.split(search, limit)
6060
exports.Symbol = Symbol
6161
exports.SymbolFor = repr => Symbol.for(repr)
62+
exports.ReflectApply = (target, self, args) => Reflect.apply(target, self, args)
6263
exports.RegExpPrototypeExec = (reg, str) => reg.exec(str)
6364
exports.RegExpPrototypeSymbolReplace = (regexp, str, replacement) =>
6465
regexp[Symbol.replace](str, replacement)

lib/internal/test_runner/test.js

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// https://github.com/nodejs/node/blob/3e57891ee2fde0971e18fc383c25acf8f90def05/lib/internal/test_runner/test.js
1+
// https://github.com/nodejs/node/blob/3759935ee29d8042d917d3ceaa768521c14413ff/lib/internal/test_runner/test.js
22

33
'use strict'
44

@@ -43,7 +43,8 @@ const {
4343
} = require('#internal/test_runner/utils')
4444
const {
4545
createDeferredPromise,
46-
kEmptyObject
46+
kEmptyObject,
47+
once: runOnce
4748
} = require('#internal/util')
4849
const { isPromise } = require('#internal/util/types')
4950
const {
@@ -486,8 +487,14 @@ class Test extends AsyncResource {
486487
return
487488
}
488489

490+
const { args, ctx } = this.getRunArgs()
491+
const afterEach = runOnce(async () => {
492+
if (this.parent?.hooks.afterEach.length > 0) {
493+
await this.parent[kRunHook]('afterEach', { args, ctx })
494+
}
495+
})
496+
489497
try {
490-
const { args, ctx } = this.getRunArgs()
491498
if (this.parent?.hooks.beforeEach.length > 0) {
492499
await this.parent[kRunHook]('beforeEach', { args, ctx })
493500
}
@@ -522,12 +529,10 @@ class Test extends AsyncResource {
522529
return
523530
}
524531

525-
if (this.parent?.hooks.afterEach.length > 0) {
526-
await this.parent[kRunHook]('afterEach', { args, ctx })
527-
}
528-
532+
await afterEach()
529533
this.pass()
530534
} catch (err) {
535+
try { await afterEach() } catch { /* test is already failing, let's the error */ }
531536
if (isTestFailureError(err)) {
532537
if (err.failureType === kTestTimeoutFailure) {
533538
this.cancel(err)
@@ -735,6 +740,12 @@ class Suite extends Test {
735740
}
736741

737742
async run () {
743+
const hookArgs = this.getRunArgs()
744+
const afterEach = runOnce(async () => {
745+
if (this.parent?.hooks.afterEach.length > 0) {
746+
await this.parent[kRunHook]('afterEach', hookArgs)
747+
}
748+
})
738749
try {
739750
this.parent.activeSubtests++
740751
await this.buildSuite
@@ -746,8 +757,6 @@ class Suite extends Test {
746757
return
747758
}
748759

749-
const hookArgs = this.getRunArgs()
750-
751760
if (this.parent?.hooks.beforeEach.length > 0) {
752761
await this.parent[kRunHook]('beforeEach', hookArgs)
753762
}
@@ -760,13 +769,11 @@ class Suite extends Test {
760769

761770
await SafePromiseRace([promise, stopPromise])
762771
await this[kRunHook]('after', hookArgs)
763-
764-
if (this.parent?.hooks.afterEach.length > 0) {
765-
await this.parent[kRunHook]('afterEach', hookArgs)
766-
}
772+
await afterEach()
767773

768774
this.pass()
769775
} catch (err) {
776+
try { await afterEach() } catch { /* test is already failing, let's the error */ }
770777
if (isTestFailureError(err)) {
771778
this.fail(err)
772779
} else {

lib/internal/util.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// https://github.com/nodejs/node/blob/a9b1fd3987fae5ad5340859a6088b86179b576c5/lib/internal/util.js
1+
// https://github.com/nodejs/node/blob/3759935ee29d8042d917d3ceaa768521c14413ff/lib/internal/util.js
22
'use strict'
33

44
const {
55
ObjectCreate,
6-
ObjectFreeze
6+
ObjectFreeze,
7+
ReflectApply
78
} = require('#internal/per_context/primordials')
89
const {
910
types: { isNativeError }
@@ -27,10 +28,20 @@ function isError (e) {
2728
return isNativeError(e) || e instanceof Error
2829
}
2930

31+
function once (callback) {
32+
let called = false
33+
return function (...args) {
34+
if (called) return
35+
called = true
36+
return ReflectApply(callback, this, args)
37+
}
38+
}
39+
3040
const kEmptyObject = ObjectFreeze(ObjectCreate(null))
3141

3242
module.exports = {
3343
createDeferredPromise,
3444
isError,
35-
kEmptyObject
45+
kEmptyObject,
46+
once
3647
}

test/message/test_runner_desctibe_it.out

-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ not ok 4 - sync fail todo with message # TODO this is a failing todo
4242
*
4343
*
4444
*
45-
*
46-
*
4745
...
4846
# Subtest: sync skip pass
4947
ok 5 - sync skip pass # SKIP

test/message/test_runner_hooks.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// https://github.com/nodejs/node/blob/a69a30016cf3395b0bd775c1340ab6ecbac58296/test/message/test_runner_hooks.js
1+
// https://github.com/nodejs/node/blob/3759935ee29d8042d917d3ceaa768521c14413ff/test/message/test_runner_hooks.js
22
// Flags: --no-warnings
33
'use strict'
4-
require('../common')
4+
const common = require('../common')
55
const assert = require('assert')
66
const { test, describe, it, before, after, beforeEach, afterEach } = require('#node:test')
77

@@ -77,6 +77,18 @@ describe('afterEach throws', () => {
7777
it('2', () => {})
7878
})
7979

80+
describe('afterEach when test fails', () => {
81+
afterEach(common.mustCall(2))
82+
it('1', () => { throw new Error('test') })
83+
it('2', () => {})
84+
})
85+
86+
describe('afterEach throws and test fails', () => {
87+
afterEach(() => { throw new Error('afterEach') })
88+
it('1', () => { throw new Error('test') })
89+
it('2', () => {})
90+
})
91+
8092
test('test hooks', async (t) => {
8193
const testArr = []
8294
t.beforeEach((t) => testArr.push('beforeEach ' + t.name))
@@ -112,3 +124,15 @@ test('t.afterEach throws', async (t) => {
112124
await t.test('1', () => {})
113125
await t.test('2', () => {})
114126
})
127+
128+
test('afterEach when test fails', async (t) => {
129+
t.afterEach(common.mustCall(2))
130+
await t.test('1', () => { throw new Error('test') })
131+
await t.test('2', () => {})
132+
})
133+
134+
test('afterEach throws and test fails', async (t) => {
135+
afterEach(() => { throw new Error('afterEach') })
136+
await t.test('1', () => { throw new Error('test') })
137+
await t.test('2', () => {})
138+
})

test/message/test_runner_hooks.out

+166-6
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,86 @@ not ok 5 - afterEach throws
189189
error: '2 subtests failed'
190190
code: 'ERR_TEST_FAILURE'
191191
...
192+
# Subtest: afterEach when test fails
193+
# Subtest: 1
194+
not ok 1 - 1
195+
---
196+
duration_ms: *
197+
failureType: 'testCodeFailure'
198+
error: 'test'
199+
code: 'ERR_TEST_FAILURE'
200+
stack: |-
201+
*
202+
*
203+
*
204+
*
205+
*
206+
*
207+
*
208+
*
209+
*
210+
*
211+
...
212+
# Subtest: 2
213+
ok 2 - 2
214+
---
215+
duration_ms: *
216+
...
217+
1..2
218+
not ok 6 - afterEach when test fails
219+
---
220+
duration_ms: *
221+
failureType: 'subtestsFailed'
222+
error: '1 subtest failed'
223+
code: 'ERR_TEST_FAILURE'
224+
...
225+
# Subtest: afterEach throws and test fails
226+
# Subtest: 1
227+
not ok 1 - 1
228+
---
229+
duration_ms: *
230+
failureType: 'testCodeFailure'
231+
error: 'test'
232+
code: 'ERR_TEST_FAILURE'
233+
stack: |-
234+
*
235+
*
236+
*
237+
*
238+
*
239+
*
240+
*
241+
*
242+
*
243+
*
244+
...
245+
# Subtest: 2
246+
not ok 2 - 2
247+
---
248+
duration_ms: *
249+
failureType: 'hookFailed'
250+
error: 'failed running afterEach hook'
251+
code: 'ERR_TEST_FAILURE'
252+
stack: |-
253+
*
254+
*
255+
*
256+
*
257+
*
258+
*
259+
*
260+
*
261+
*
262+
*
263+
...
264+
1..2
265+
not ok 7 - afterEach throws and test fails
266+
---
267+
duration_ms: *
268+
failureType: 'subtestsFailed'
269+
error: '2 subtests failed'
270+
code: 'ERR_TEST_FAILURE'
271+
...
192272
# Subtest: test hooks
193273
# Subtest: 1
194274
ok 1 - 1
@@ -217,7 +297,7 @@ not ok 5 - afterEach throws
217297
duration_ms: *
218298
...
219299
1..3
220-
ok 6 - test hooks
300+
ok 8 - test hooks
221301
---
222302
duration_ms: *
223303
...
@@ -261,7 +341,7 @@ ok 6 - test hooks
261341
*
262342
...
263343
1..2
264-
not ok 7 - t.beforeEach throws
344+
not ok 9 - t.beforeEach throws
265345
---
266346
duration_ms: *
267347
failureType: 'subtestsFailed'
@@ -308,17 +388,97 @@ not ok 7 - t.beforeEach throws
308388
*
309389
...
310390
1..2
311-
not ok 8 - t.afterEach throws
391+
not ok 10 - t.afterEach throws
392+
---
393+
duration_ms: *
394+
failureType: 'subtestsFailed'
395+
error: '2 subtests failed'
396+
code: 'ERR_TEST_FAILURE'
397+
...
398+
# Subtest: afterEach when test fails
399+
# Subtest: 1
400+
not ok 1 - 1
401+
---
402+
duration_ms: *
403+
failureType: 'testCodeFailure'
404+
error: 'test'
405+
code: 'ERR_TEST_FAILURE'
406+
stack: |-
407+
*
408+
*
409+
*
410+
*
411+
*
412+
*
413+
*
414+
*
415+
*
416+
*
417+
...
418+
# Subtest: 2
419+
ok 2 - 2
420+
---
421+
duration_ms: *
422+
...
423+
1..2
424+
not ok 11 - afterEach when test fails
425+
---
426+
duration_ms: *
427+
failureType: 'subtestsFailed'
428+
error: '1 subtest failed'
429+
code: 'ERR_TEST_FAILURE'
430+
...
431+
# Subtest: afterEach throws and test fails
432+
# Subtest: 1
433+
not ok 1 - 1
434+
---
435+
duration_ms: *
436+
failureType: 'testCodeFailure'
437+
error: 'test'
438+
code: 'ERR_TEST_FAILURE'
439+
stack: |-
440+
*
441+
*
442+
*
443+
*
444+
*
445+
*
446+
*
447+
*
448+
*
449+
*
450+
...
451+
# Subtest: 2
452+
not ok 2 - 2
453+
---
454+
duration_ms: *
455+
failureType: 'hookFailed'
456+
error: 'failed running afterEach hook'
457+
code: 'ERR_TEST_FAILURE'
458+
stack: |-
459+
*
460+
*
461+
*
462+
*
463+
*
464+
*
465+
*
466+
*
467+
*
468+
*
469+
...
470+
1..2
471+
not ok 12 - afterEach throws and test fails
312472
---
313473
duration_ms: *
314474
failureType: 'subtestsFailed'
315475
error: '2 subtests failed'
316476
code: 'ERR_TEST_FAILURE'
317477
...
318-
1..8
319-
# tests 8
478+
1..12
479+
# tests 12
320480
# pass 2
321-
# fail 6
481+
# fail 10
322482
# cancelled 0
323483
# skipped 0
324484
# todo 0

test/message/test_runner_output.out

-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ not ok 4 - sync fail todo with message # TODO this is a failing todo
4242
*
4343
*
4444
*
45-
*
46-
*
4745
...
4846
# Subtest: sync skip pass
4947
ok 5 - sync skip pass # SKIP

0 commit comments

Comments
 (0)