Skip to content

Commit

Permalink
lib: allow checking the test result from afterEach
Browse files Browse the repository at this point in the history
PR-URL: #51485
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
  • Loading branch information
tims-bsquare authored and targos committed Feb 15, 2024
1 parent 391aeb1 commit 4b583bf
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 14 deletions.
23 changes: 19 additions & 4 deletions lib/internal/test_runner/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ class TestContext {
return this.#test.name;
}

get error() {
return this.#test.error;
}

get passed() {
return this.#test.passed;
}

diagnostic(message) {
this.#test.diagnostic(message);
}
Expand Down Expand Up @@ -639,12 +647,17 @@ class Test extends AsyncResource {
return;
}

await afterEach();
await after();
this.pass();
try {
await afterEach();
await after();
} catch (err) {
// If one of the after hooks has thrown unset endTime so that the
// catch below can do its cancel/fail logic.
this.endTime = null;
throw err;
}
} catch (err) {
try { await afterEach(); } catch { /* test is already failing, let's ignore the error */ }
try { await after(); } catch { /* Ignore error. */ }
if (isTestFailureError(err)) {
if (err.failureType === kTestTimeoutFailure) {
this.#cancel(err);
Expand All @@ -654,6 +667,8 @@ class Test extends AsyncResource {
} else {
this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
}
try { await afterEach(); } catch { /* test is already failing, let's ignore the error */ }
try { await after(); } catch { /* Ignore error. */ }
} finally {
stopPromise?.[SymbolDispose]();

Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/test-runner/output/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ test('afterEach when test fails', async (t) => {
await t.test('2', () => {});
});

test('afterEach context when test passes', async (t) => {
t.afterEach(common.mustCall((ctx) => {
assert.strictEqual(ctx.name, '1');
assert.strictEqual(ctx.passed, true);
assert.strictEqual(ctx.error, null);
}));
await t.test('1', () => {});
});

test('afterEach context when test fails', async (t) => {
const err = new Error('test');
t.afterEach(common.mustCall((ctx) => {
assert.strictEqual(ctx.name, '1');
assert.strictEqual(ctx.passed, false);
assert.strictEqual(ctx.error, err);
}));
await t.test('1', () => { throw err });
});

test('afterEach throws and test fails', async (t) => {
t.after(common.mustCall());
t.afterEach(() => { throw new Error('afterEach'); });
Expand Down
49 changes: 42 additions & 7 deletions test/fixtures/test-runner/output/hooks.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,41 @@ not ok 12 - afterEach when test fails
error: '1 subtest failed'
code: 'ERR_TEST_FAILURE'
...
# Subtest: afterEach context when test passes
# Subtest: 1
ok 1 - 1
---
duration_ms: *
...
1..1
ok 13 - afterEach context when test passes
---
duration_ms: *
...
# Subtest: afterEach context when test fails
# Subtest: 1
not ok 1 - 1
---
duration_ms: *
location: '/test/fixtures/test-runner/output/hooks.js:(LINE):11'
failureType: 'testCodeFailure'
error: 'test'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
...
1..1
not ok 14 - afterEach context when test fails
---
duration_ms: *
location: '/test/fixtures/test-runner/output/hooks.js:(LINE):1'
failureType: 'subtestsFailed'
error: '1 subtest failed'
code: 'ERR_TEST_FAILURE'
...
# Subtest: afterEach throws and test fails
# Subtest: 1
not ok 1 - 1
Expand Down Expand Up @@ -546,7 +581,7 @@ not ok 12 - afterEach when test fails
*
...
1..2
not ok 13 - afterEach throws and test fails
not ok 15 - afterEach throws and test fails
---
duration_ms: *
location: '/test/fixtures/test-runner/output/hooks.js:(LINE):1'
Expand All @@ -555,7 +590,7 @@ not ok 13 - afterEach throws and test fails
code: 'ERR_TEST_FAILURE'
...
# Subtest: t.after() is called if test body throws
not ok 14 - t.after() is called if test body throws
not ok 16 - t.after() is called if test body throws
---
duration_ms: *
location: '/test/fixtures/test-runner/output/hooks.js:(LINE):1'
Expand All @@ -580,7 +615,7 @@ not ok 14 - t.after() is called if test body throws
code: 'ERR_TEST_FAILURE'
...
1..1
not ok 15 - run after when before throws
not ok 17 - run after when before throws
---
duration_ms: *
type: 'suite'
Expand All @@ -599,15 +634,15 @@ not ok 15 - run after when before throws
*
*
...
1..15
1..17
# before 1 called
# before 2 called
# after 1 called
# after 2 called
# tests 39
# tests 43
# suites 9
# pass 14
# fail 22
# pass 16
# fail 24
# cancelled 3
# skipped 0
# todo 0
Expand Down
28 changes: 25 additions & 3 deletions test/fixtures/test-runner/output/hooks_spec_reporter.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,20 @@
2 (*ms)
afterEach when test fails (*ms)

afterEach context when test passes
1 (*ms)
afterEach context when test passes (*ms)

afterEach context when test fails
1 (*ms)
Error: test
*
*
*
*

afterEach context when test fails (*ms)

afterEach throws and test fails
1 (*ms)
Error: test
Expand Down Expand Up @@ -315,10 +329,10 @@
before 2 called
after 1 called
after 2 called
tests 39
tests 43
suites 9
pass 14
fail 22
pass 16
fail 24
cancelled 3
skipped 0
todo 0
Expand Down Expand Up @@ -551,6 +565,14 @@
*
*

*
1 (*ms)
Error: test
*
*
*
*

*
1 (*ms)
Error: test
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/test-runner/output/junit_reporter.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ true !== false
<testcase name="+sync throw fail" time="*" classname="test" failure="thrown from subtest sync throw fail">
<failure type="testCodeFailure" message="thrown from subtest sync throw fail">
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail
*
* {
code: 'ERR_TEST_FAILURE',
failureType: 'testCodeFailure',
Expand Down Expand Up @@ -338,6 +339,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw
<testcase name="sync throw fails at first" time="*" classname="test" failure="thrown from subtest sync throw fails at first">
<failure type="testCodeFailure" message="thrown from subtest sync throw fails at first">
Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first
*
* {
code: 'ERR_TEST_FAILURE',
failureType: 'testCodeFailure',
Expand Down

0 comments on commit 4b583bf

Please sign in to comment.