Skip to content

Commit 290bd0f

Browse files
committed
test_runner: add before/after/each hooks
1 parent 7abbbf2 commit 290bd0f

9 files changed

+688
-36
lines changed

doc/api/test.md

+194
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,120 @@ same as [`it([name], { skip: true }[, fn])`][it options].
446446
Shorthand for marking a test as `TODO`,
447447
same as [`it([name], { todo: true }[, fn])`][it options].
448448

449+
### `before([, fn][, options])`
450+
451+
<!-- YAML
452+
added: REPLACEME
453+
-->
454+
455+
* `fn` {Function|AsyncFunction} The hook function.
456+
If the hook uses callbacks,
457+
the callback function is passed as the second argument. **Default:** A no-op
458+
function.
459+
* `options` {Object} Configuration options for the hook. The following
460+
properties are supported:
461+
* `signal` {AbortSignal} Allows aborting an in-progress hook
462+
* `timeout` {number} A number of milliseconds the hook will fail after.
463+
If unspecified, subtests inherit this value from their parent.
464+
**Default:** `Infinity`.
465+
466+
This function is used to create a hook running before running a suite.
467+
468+
```js
469+
describe('tests', async () => {
470+
before(() => console.log('about to run some test'));
471+
it('is a subtest', () => {
472+
assert.ok('some relevant assertion here');
473+
});
474+
});
475+
```
476+
477+
### `after([, fn][, options])`
478+
479+
<!-- YAML
480+
added: REPLACEME
481+
-->
482+
483+
* `fn` {Function|AsyncFunction} The hook function.
484+
If the hook uses callbacks,
485+
the callback function is passed as the second argument. **Default:** A no-op
486+
function.
487+
* `options` {Object} Configuration options for the hook. The following
488+
properties are supported:
489+
* `signal` {AbortSignal} Allows aborting an in-progress hook
490+
* `timeout` {number} A number of milliseconds the hook will fail after.
491+
If unspecified, subtests inherit this value from their parent.
492+
**Default:** `Infinity`.
493+
494+
This function is used to create a hook running after running a suite.
495+
496+
```js
497+
describe('tests', async () => {
498+
after(() => console.log('finished running tests'));
499+
it('is a subtest', () => {
500+
assert.ok('some relevant assertion here');
501+
});
502+
});
503+
```
504+
505+
### `beforeEach([, fn][, options])`
506+
507+
<!-- YAML
508+
added: REPLACEME
509+
-->
510+
511+
* `fn` {Function|AsyncFunction} The hook function.
512+
If the hook uses callbacks,
513+
the callback function is passed as the second argument. **Default:** A no-op
514+
function.
515+
* `options` {Object} Configuration options for the hook. The following
516+
properties are supported:
517+
* `signal` {AbortSignal} Allows aborting an in-progress hook
518+
* `timeout` {number} A number of milliseconds the hook will fail after.
519+
If unspecified, subtests inherit this value from their parent.
520+
**Default:** `Infinity`.
521+
522+
This function is used to create a hook running
523+
before each subtest of the current suite.
524+
525+
```js
526+
describe('tests', async () => {
527+
beforeEach(() => t.diagnostics('about to run a test'));
528+
it('is a subtest', () => {
529+
assert.ok('some relevant assertion here');
530+
});
531+
});
532+
```
533+
534+
### `afterEach([, fn][, options])`
535+
536+
<!-- YAML
537+
added: REPLACEME
538+
-->
539+
540+
* `fn` {Function|AsyncFunction} The hook function.
541+
If the hook uses callbacks,
542+
the callback function is passed as the second argument. **Default:** A no-op
543+
function.
544+
* `options` {Object} Configuration options for the hook. The following
545+
properties are supported:
546+
* `signal` {AbortSignal} Allows aborting an in-progress hook
547+
* `timeout` {number} A number of milliseconds the hook will fail after.
548+
If unspecified, subtests inherit this value from their parent.
549+
**Default:** `Infinity`.
550+
551+
This function is used to create a hook running
552+
after each subtest of the current test.
553+
554+
```js
555+
describe('tests', async () => {
556+
afterEach(() => t.diagnostics('about to run a test'));
557+
it('is a subtest', () => {
558+
assert.ok('some relevant assertion here');
559+
});
560+
});
561+
```
562+
449563
## Class: `TestContext`
450564

451565
<!-- YAML
@@ -456,6 +570,70 @@ An instance of `TestContext` is passed to each test function in order to
456570
interact with the test runner. However, the `TestContext` constructor is not
457571
exposed as part of the API.
458572

573+
### `context.beforeEach([, fn][, options])`
574+
575+
<!-- YAML
576+
added: REPLACEME
577+
-->
578+
579+
* `fn` {Function|AsyncFunction} The hook function. The first argument
580+
to this function is a [`TestContext`][] object. If the hook uses callbacks,
581+
the callback function is passed as the second argument. **Default:** A no-op
582+
function.
583+
* `options` {Object} Configuration options for the hook. The following
584+
properties are supported:
585+
* `signal` {AbortSignal} Allows aborting an in-progress hook
586+
* `timeout` {number} A number of milliseconds the hook will fail after.
587+
If unspecified, subtests inherit this value from their parent.
588+
**Default:** `Infinity`.
589+
590+
This function is used to create a hook running
591+
before each subtest of the current test.
592+
593+
```js
594+
test('top level test', async (t) => {
595+
t.beforeEach((t) => t.diagnostics(`about to run ${t.name}`));
596+
await t.test(
597+
'This is a subtest',
598+
(t) => {
599+
assert.ok('some relevant assertion here');
600+
}
601+
);
602+
});
603+
```
604+
605+
### `context.afterEach([, fn][, options])`
606+
607+
<!-- YAML
608+
added: REPLACEME
609+
-->
610+
611+
* `fn` {Function|AsyncFunction} The hook function. The first argument
612+
to this function is a [`TestContext`][] object. If the hook uses callbacks,
613+
the callback function is passed as the second argument. **Default:** A no-op
614+
function.
615+
* `options` {Object} Configuration options for the hook. The following
616+
properties are supported:
617+
* `signal` {AbortSignal} Allows aborting an in-progress hook
618+
* `timeout` {number} A number of milliseconds the hook will fail after.
619+
If unspecified, subtests inherit this value from their parent.
620+
**Default:** `Infinity`.
621+
622+
This function is used to create a hook running
623+
after each subtest of the current test.
624+
625+
```js
626+
test('top level test', async (t) => {
627+
t.afterEach((t) => t.diagnostics(`finished running ${t.name}`));
628+
await t.test(
629+
'This is a subtest',
630+
(t) => {
631+
assert.ok('some relevant assertion here');
632+
}
633+
);
634+
});
635+
```
636+
459637
### `context.diagnostic(message)`
460638

461639
<!-- YAML
@@ -474,6 +652,14 @@ test('top level test', (t) => {
474652
});
475653
```
476654

655+
### `context.name`
656+
657+
<!-- YAML
658+
added: REPLACEME
659+
-->
660+
661+
The name of the test
662+
477663
### `context.runOnly(shouldRunOnlyTests)`
478664

479665
<!-- YAML
@@ -616,6 +802,14 @@ An instance of `SuiteContext` is passed to each suite function in order to
616802
interact with the test runner. However, the `SuiteContext` constructor is not
617803
exposed as part of the API.
618804

805+
### `context.name`
806+
807+
<!-- YAML
808+
added: REPLACEME
809+
-->
810+
811+
The name of the suite
812+
619813
### `context.signal`
620814

621815
<!-- YAML

lib/internal/test_runner/harness.js

+11
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,19 @@ function runInParentContext(Factory) {
170170
return cb;
171171
}
172172

173+
function hook(hook) {
174+
return (fn, options) => {
175+
const parent = testResources.get(executionAsyncId()) || setup(root);
176+
parent.createHook(hook, fn, options);
177+
};
178+
}
179+
173180
module.exports = {
174181
test: FunctionPrototypeBind(test, root),
175182
describe: runInParentContext(Suite),
176183
it: runInParentContext(ItTest),
184+
before: hook('before'),
185+
after: hook('after'),
186+
beforeEach: hook('beforeEach'),
187+
afterEach: hook('afterEach'),
177188
};

0 commit comments

Comments
 (0)