Skip to content

Commit

Permalink
test_runner: execute before hook on test
Browse files Browse the repository at this point in the history
Execute the before hook for Test as well, and execute it on root before
executing any tests.

Fixes: #47518
  • Loading branch information
atlowChemi committed Apr 16, 2023
1 parent 070c9a8 commit 6c9fc93
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 11 deletions.
14 changes: 12 additions & 2 deletions lib/internal/test_runner/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ class TestContext {
return subtest.start();
}

before(fn, options) {
this.#test.createHook('before', fn, options);
}

after(fn, options) {
this.#test.createHook('after', fn, options);
}
Expand Down Expand Up @@ -414,6 +418,9 @@ class Test extends AsyncResource {
validateOneOf(name, 'hook name', kHookNames);
// eslint-disable-next-line no-use-before-define
const hook = new TestHook(fn, options);
if (name === 'before') {
hook.run = runOnce(hook.run);
}
ArrayPrototypePush(this.hooks[name], hook);
return hook;
}
Expand Down Expand Up @@ -525,6 +532,9 @@ class Test extends AsyncResource {
if (this.parent?.hooks.beforeEach.length > 0) {
await this.parent.runHook('beforeEach', { args, ctx });
}
if (this.parent?.hooks.before.length > 0) {
await this.parent.runHook('before', this.parent.getRunArgs());
}
const stopPromise = stopTest(this.timeout, this.signal);
const runArgs = ArrayPrototypeSlice(args);
ArrayPrototypeUnshift(runArgs, this.fn, ctx);
Expand Down Expand Up @@ -561,7 +571,7 @@ class Test extends AsyncResource {
this.pass();
} catch (err) {
try { await after(); } catch { /* Ignore error. */ }
try { await afterEach(); } catch { /* test is already failing, let's the error */ }
try { await afterEach(); } catch { /* test is already failing, let's ignore the error */ }
if (isTestFailureError(err)) {
if (err.failureType === kTestTimeoutFailure) {
this.#cancel(err);
Expand Down Expand Up @@ -793,7 +803,7 @@ class Suite extends Test {

this.pass();
} catch (err) {
try { await afterEach(); } catch { /* test is already failing, let's the error */ }
try { await afterEach(); } catch { /* test is already failing, let's ignore the error */ }
if (isTestFailureError(err)) {
this.fail(err);
} else {
Expand Down
10 changes: 9 additions & 1 deletion test/fixtures/test-runner/output/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ describe('afterEach throws and test fails', () => {
test('test hooks', async (t) => {
const testArr = [];

t.before((t) => testArr.push('before ' + t.name));
t.after(common.mustCall((t) => testArr.push('after ' + t.name)));
t.beforeEach((t) => testArr.push('beforeEach ' + t.name));
t.afterEach((t) => testArr.push('afterEach ' + t.name));
Expand All @@ -105,7 +106,7 @@ test('test hooks', async (t) => {
});

assert.deepStrictEqual(testArr, [
'beforeEach 1', '1', 'afterEach 1',
'beforeEach 1', 'before test hooks', '1', 'afterEach 1',
'beforeEach 2', '2', 'afterEach 2',
'beforeEach nested',
'nested beforeEach nested 1', 'nested1', 'nested afterEach nested 1',
Expand All @@ -114,6 +115,13 @@ test('test hooks', async (t) => {
]);
});

test('t.before throws', async (t) => {
t.after(common.mustCall());
t.before(() => { throw new Error('before'); });
await t.test('1', () => {});
await t.test('2', () => {});
});

test('t.beforeEach throws', async (t) => {
t.after(common.mustCall());
t.beforeEach(() => { throw new Error('beforeEach'); });
Expand Down
64 changes: 56 additions & 8 deletions test/fixtures/test-runner/output/hooks.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ not ok 2 - before throws
*
*
*
*
...
# Subtest: after throws
# Subtest: 1
Expand Down Expand Up @@ -307,6 +308,53 @@ ok 8 - test hooks
---
duration_ms: *
...
# Subtest: t.before throws
# Subtest: 1
not ok 1 - 1
---
duration_ms: *
failureType: 'hookFailed'
error: 'failed running before hook'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
*
*
*
*
*
*
...
# Subtest: 2
not ok 2 - 2
---
duration_ms: *
failureType: 'hookFailed'
error: 'failed running before hook'
code: 'ERR_TEST_FAILURE'
stack: |-
*
*
*
*
*
*
*
*
*
*
...
1..2
not ok 9 - t.before throws
---
duration_ms: *
failureType: 'subtestsFailed'
error: '2 subtests failed'
code: 'ERR_TEST_FAILURE'
...
# Subtest: t.beforeEach throws
# Subtest: 1
not ok 1 - 1
Expand Down Expand Up @@ -347,7 +395,7 @@ ok 8 - test hooks
*
...
1..2
not ok 9 - t.beforeEach throws
not ok 10 - t.beforeEach throws
---
duration_ms: *
failureType: 'subtestsFailed'
Expand Down Expand Up @@ -394,7 +442,7 @@ not ok 9 - t.beforeEach throws
*
...
1..2
not ok 10 - t.afterEach throws
not ok 11 - t.afterEach throws
---
duration_ms: *
failureType: 'subtestsFailed'
Expand Down Expand Up @@ -427,7 +475,7 @@ not ok 10 - t.afterEach throws
duration_ms: *
...
1..2
not ok 11 - afterEach when test fails
not ok 12 - afterEach when test fails
---
duration_ms: *
failureType: 'subtestsFailed'
Expand Down Expand Up @@ -474,15 +522,15 @@ not ok 11 - afterEach when test fails
*
...
1..2
not ok 12 - afterEach throws and test fails
not ok 13 - afterEach throws and test fails
---
duration_ms: *
failureType: 'subtestsFailed'
error: '2 subtests failed'
code: 'ERR_TEST_FAILURE'
...
# Subtest: t.after() is called if test body throws
not ok 13 - t.after() is called if test body throws
not ok 14 - t.after() is called if test body throws
---
duration_ms: *
failureType: 'testCodeFailure'
Expand All @@ -498,11 +546,11 @@ not ok 13 - t.after() is called if test body throws
*
...
# - after() called
1..13
# tests 35
1..14
# tests 38
# suites 8
# pass 14
# fail 19
# fail 22
# cancelled 2
# skipped 0
# todo 0
Expand Down

0 comments on commit 6c9fc93

Please sign in to comment.