Using Node.js's test runner
Node.js has a flexible and robust built-in test runner. This guide will show you how to set up and use it.
example/
├ …
├ src/
├ app/…
└ sw/…
└ test/
├ globals/
├ …
├ IndexedDb.js
└ ServiceWorkerGlobalScope.js
├ setup.mjs
├ setup.units.mjs
└ setup.ui.mjs
Note: globs require node v21+, and the globs must themselves be wrapped in quotes (without, you'll get different behaviour than expected, wherein it may first appear to be working but isn't).
There are some things you always want, so put them in a base setup file like the following. This file will get imported by other, more bespoke setups.
General setup
import { function register<Data = any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<Data>): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register } from 'node:module';
register<any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<any> | undefined): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register('some-typescript-loader');
// TypeScript is supported hereafter
// BUT other test/setup.*.mjs files still must be plain JavaScript!
Then for each setup, create a dedicated setup file (ensuring the base setup.mjs file is imported within each). There are a number of reasons to isolate the setups, but the most obvious reason is YAGNI + performance: much of what you may be setting up are environment-specific mocks/stubs, which can be quite expensive and will slow down test runs. You want to avoid those costs (literal money you pay to CI, time waiting for tests to finish, etc) when you don't need them.
Each example below was taken from real-world projects; they may not be appropriate/applicable to yours, but each demonstrate general concepts that are broadly applicable.
Dynamically generating test cases
Some times, you may want to dynamically generate test-cases. For instance, you want to test the same thing across a bunch of files. This is possible, albeit slightly arcane. You must use test (you cannot use describe) + testContext.test:
Simple example
import const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert from 'node:assert/strict';
import { function test(name?: string, fn?: test.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test } from 'node:test';
import { import detectOsInUserAgentdetectOsInUserAgent } from '…';
const const userAgents: {
ua: string;
os: string;
}[]
userAgents = [
{
ua: stringua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3',
os: stringos: 'WIN',
},
// …
];
function test(name?: string, options?: test.TestOptions, fn?: test.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test('Detect OS via user-agent', { test.TestOptions.concurrency?: number | boolean | undefinedIf a number is provided, then that many tests would run in parallel.
If truthy, it would run (number of cpu cores - 1) tests in parallel.
For subtests, it will be `Infinity` tests in parallel.
If falsy, it would only run one test at a time.
If unspecified, subtests inherit this value from their parent.concurrency: true }, t: test.TestContextt => {
for (const { const os: stringos, const ua: stringua } of const userAgents: {
ua: string;
os: string;
}[]
userAgents) {
t: test.TestContextt.test.TestContext.test: (name?: string, fn?: test.TestFn) => Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test(const ua: stringua, () => const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.equal: <string>(actual: unknown, expected: string, message?: string | Error) => asserts actual is stringTests strict equality between the `actual` and `expected` parameters as
determined by [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
```js
import assert from 'node:assert/strict';
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
// ^
const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
```
If the values are not strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a
default error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
instead of the `AssertionError`.equal(import detectOsInUserAgentdetectOsInUserAgent(const ua: stringua), const os: stringos));
}
});
Advanced example
import const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert from 'node:assert/strict';
import { function test(name?: string, fn?: test.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test } from 'node:test';
import { import getWorkspacePJSONsgetWorkspacePJSONs } from './getWorkspacePJSONs.mjs';
const const requiredKeywords: string[]requiredKeywords = ['node.js', 'sliced bread'];
function test(name?: string, options?: test.TestOptions, fn?: test.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test('Check package.jsons', { test.TestOptions.concurrency?: number | boolean | undefinedIf a number is provided, then that many tests would run in parallel.
If truthy, it would run (number of cpu cores - 1) tests in parallel.
For subtests, it will be `Infinity` tests in parallel.
If falsy, it would only run one test at a time.
If unspecified, subtests inherit this value from their parent.concurrency: true }, async t: test.TestContextt => {
const const pjsons: anypjsons = await import getWorkspacePJSONsgetWorkspacePJSONs();
for (const const pjson: anypjson of const pjsons: anypjsons) {
// ⚠️ `t.test`, NOT `test`
t: test.TestContextt.test.TestContext.test: (name?: string, fn?: test.TestFn) => Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.test(`Ensure fields are properly set: ${const pjson: anypjson.name}`, () => {
const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.partialDeepStrictEqual: (actual: unknown, expected: unknown, message?: string | Error) => voidTests for partial deep equality between the `actual` and `expected` parameters.
"Deep" equality means that the enumerable "own" properties of child objects
are recursively evaluated also by the following rules. "Partial" equality means
that only properties that exist on the `expected` parameter are going to be
compared.
This method always passes the same test cases as `assert.deepStrictEqual()`,
behaving as a super set of it.partialDeepStrictEqual(const pjson: anypjson.keywords, const requiredKeywords: string[]requiredKeywords);
});
}
});
Note: Prior to version 23.8.0, the setup is quite different because
testContext.testwas not automatically awaited.
ServiceWorker tests
ServiceWorkerGlobalScope contains very specific APIs that don't exist in other environments, and some of its APIs are seemingly similar to others (ex fetch) but have augmented behaviour. You do not want these to spill into unrelated tests.
import { function beforeEach(fn?: test.HookFn, options?: test.HookOptions): voidThis function creates a hook that runs before each test in the current suite.
```js
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
```beforeEach } from 'node:test';
import { import ServiceWorkerGlobalScopeServiceWorkerGlobalScope } from './globals/ServiceWorkerGlobalScope.js';
import './setup.mjs'; // 💡
function beforeEach(fn?: test.HookFn, options?: test.HookOptions): voidThis function creates a hook that runs before each test in the current suite.
```js
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
```beforeEach(function globalSWBeforeEach(): voidglobalSWBeforeEach);
function function globalSWBeforeEach(): voidglobalSWBeforeEach() {
module globalThisglobalThis.var self: Window & typeof globalThis[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/self)self = new import ServiceWorkerGlobalScopeServiceWorkerGlobalScope();
}
import const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert from 'node:assert/strict';
import { function describe(name?: string, options?: it.TestOptions, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe, const mock: it.MockTrackermock, function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it } from 'node:test';
import { import onActivateonActivate } from './onActivate.js';
function describe(name?: string, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe('ServiceWorker::onActivate()', () => {
const const globalSelf: Window & typeof globalThisglobalSelf = module globalThisglobalThis.var self: Window & typeof globalThis[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/self)self;
const const claim: it.Mock<() => Promise<void>>claim = const mock: it.MockTrackermock.test.MockTracker.fn<() => Promise<void>>(original?: (() => Promise<void>) | undefined, options?: it.MockFunctionOptions): it.Mock<() => Promise<void>> (+1 overload)This function is used to create a mock function.
The following example creates a mock function that increments a counter by one
on each invocation. The `times` option is used to modify the mock behavior such
that the first two invocations add two to the counter instead of one.
```js
test('mocks a counting function', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 });
assert.strictEqual(fn(), 2);
assert.strictEqual(fn(), 4);
assert.strictEqual(fn(), 5);
assert.strictEqual(fn(), 6);
});
```fn(async function function (local function) mock__claim(): Promise<void>mock__claim() {});
const const matchAll: it.Mock<() => Promise<void>>matchAll = const mock: it.MockTrackermock.test.MockTracker.fn<() => Promise<void>>(original?: (() => Promise<void>) | undefined, options?: it.MockFunctionOptions): it.Mock<() => Promise<void>> (+1 overload)This function is used to create a mock function.
The following example creates a mock function that increments a counter by one
on each invocation. The `times` option is used to modify the mock behavior such
that the first two invocations add two to the counter instead of one.
```js
test('mocks a counting function', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 });
assert.strictEqual(fn(), 2);
assert.strictEqual(fn(), 4);
assert.strictEqual(fn(), 5);
assert.strictEqual(fn(), 6);
});
```fn(async function function (local function) mock__matchAll(): Promise<void>mock__matchAll() {});
class class ActivateEventActivateEvent extends var Event: {
new (type: string, eventInitDict?: EventInit): Event;
prototype: Event;
readonly NONE: 0;
readonly CAPTURING_PHASE: 1;
readonly AT_TARGET: 2;
readonly BUBBLING_PHASE: 3;
}
An event which takes place in the DOM.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Event)Event {
constructor(...args: any[]args) {
super('activate', ...args: any[]args);
}
}
before(() => {
module globalThisglobalThis.var self: Window & typeof globalThis[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/self)self = {
clients: {
claim: it.Mock<() => Promise<void>>;
matchAll: it.Mock<() => Promise<void>>;
}
clients: { claim: it.Mock<() => Promise<void>>claim, matchAll: it.Mock<() => Promise<void>>matchAll },
};
});
after(() => {
var global: typeof globalThisglobal.var self: Window & typeof globalThis[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/self)self = const globalSelf: Window & typeof globalThisglobalSelf;
});
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should claim all clients', async () => {
await import onActivateonActivate(new constructor ActivateEvent(...args: any[]): ActivateEventActivateEvent());
const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.equal: <1>(actual: unknown, expected: 1, message?: string | Error) => asserts actual is 1Tests strict equality between the `actual` and `expected` parameters as
determined by [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
```js
import assert from 'node:assert/strict';
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
// ^
const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
```
If the values are not strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a
default error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
instead of the `AssertionError`.equal(const claim: it.Mock<() => Promise<void>>claim.mock: it.MockFunctionContext<() => Promise<void>>mock.test.MockFunctionContext<() => Promise<void>>.callCount(): numberThis function returns the number of times that this mock has been invoked. This
function is more efficient than checking `ctx.calls.length` because `ctx.calls` is a getter that creates a copy of the internal call tracking array.callCount(), 1);
const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.equal: <1>(actual: unknown, expected: 1, message?: string | Error) => asserts actual is 1Tests strict equality between the `actual` and `expected` parameters as
determined by [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
```js
import assert from 'node:assert/strict';
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
// ^
const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
```
If the values are not strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a
default error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
instead of the `AssertionError`.equal(const matchAll: it.Mock<() => Promise<void>>matchAll.mock: it.MockFunctionContext<() => Promise<void>>mock.test.MockFunctionContext<() => Promise<void>>.callCount(): numberThis function returns the number of times that this mock has been invoked. This
function is more efficient than checking `ctx.calls.length` because `ctx.calls` is a getter that creates a copy of the internal call tracking array.callCount(), 1);
});
});
Snapshot tests
These were popularised by Jest; now, many libraries implement such functionality, including Node.js as of v22.3.0. There are several use-cases such as verifying component rendering output and Infrastructure as Code config. The concept is the same regardless of use-case.
There is no specific configuration required except enabling the feature via --experimental-test-snapshots. But to demonstrate the optional configuration, you would probably add something like the following to one of your existing test config files.
By default, node generates a filename that is incompatible with syntax highlighting detection: .js.snapshot. The generated file is actually a CJS file, so a more appropriate file name would end with .snapshot.cjs (or more succinctly .snap.cjs as below); this will also handle better in ESM projects.
import { function (method) basename(path: string, suffix?: string): stringReturn the last portion of a path. Similar to the Unix basename command.
Often used to extract the file name from a fully qualified path.basename, function (method) dirname(path: string): stringReturn the directory name of a path. Similar to the Unix dirname command.dirname, function (method) extname(path: string): stringReturn the extension of the path, from the last '.' to end of string in the last portion of the path.
If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string.extname, function (method) join(...paths: string[]): stringJoin all arguments together and normalize the resulting path.join } from 'node:path';
import { snapshot } from 'node:test';
snapshot.function test.snapshot.setResolveSnapshotPath(fn: (path: string | undefined) => string): voidThis function is used to set a custom resolver for the location of the snapshot file used for snapshot testing.
By default, the snapshot filename is the same as the entry point filename with `.snapshot` appended.setResolveSnapshotPath(function generateSnapshotPath(testFilePath: string): stringgenerateSnapshotPath);
/**
* @param {string} testFilePath '/tmp/foo.test.js'
* @returns {string} '/tmp/foo.test.snap.cjs'
*/
function function generateSnapshotPath(testFilePath: string): stringgenerateSnapshotPath(testFilePath: string'/tmp/foo.test.js'testFilePath) {
const const ext: stringext = function extname(path: string): stringReturn the extension of the path, from the last '.' to end of string in the last portion of the path.
If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string.extname(testFilePath: string'/tmp/foo.test.js'testFilePath);
const const filename: stringfilename = function basename(path: string, suffix?: string): stringReturn the last portion of a path. Similar to the Unix basename command.
Often used to extract the file name from a fully qualified path.basename(testFilePath: string'/tmp/foo.test.js'testFilePath, const ext: stringext);
const const base: stringbase = function dirname(path: string): stringReturn the directory name of a path. Similar to the Unix dirname command.dirname(testFilePath: string'/tmp/foo.test.js'testFilePath);
return function join(...paths: string[]): stringJoin all arguments together and normalize the resulting path.join(const base: stringbase, `${const filename: stringfilename}.snap.cjs`);
}
The example below demonstrates snapshot testing with testing library for UI components; note the two different ways of accessing assert.snapshot):
import { function describe(name?: string, options?: it.TestOptions, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe, function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it } from 'node:test';
import { import prettyDOMprettyDOM } from '@testing-library/dom';
import { import renderrender } from '@testing-library/react'; // Any framework (ex svelte)
import { import SomeComponentSomeComponent } from './SomeComponent.jsx';
function describe(name?: string, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe('<SomeComponent>', () => {
// For people preferring "fat-arrow" syntax, the following is probably better for consistency
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should render defaults when no props are provided', t: it.TestContextt => {
const const component: anycomponent = import renderrender(<import SomeComponentSomeComponent />).container.firstChild;
t: it.TestContextt.test.TestContext.assert: it.TestContextAssertAn object containing assertion methods bound to the test context.
The top-level functions from the `node:assert` module are exposed here for the purpose of creating test plans.
**Note:** Some of the functions from `node:assert` contain type assertions. If these are called via the
TestContext `assert` object, then the context parameter in the test's function signature **must be explicitly typed**
(ie. the parameter must have a type annotation), otherwise an error will be raised by the TypeScript compiler:
```ts
import { test, type TestContext } from 'node:test';
// The test function's context parameter must have a type annotation.
test('example', (t: TestContext) => {
t.assert.deepStrictEqual(actual, expected);
});
// Omitting the type annotation will result in a compilation error.
test('example', t => {
t.assert.deepStrictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
});
```assert.test.TestContextAssert.snapshot(value: any, options?: it.AssertSnapshotOptions): voidThis function implements assertions for snapshot testing.
```js
test('snapshot test with default serialization', (t) => {
t.assert.snapshot({ value1: 1, value2: 2 });
});
test('snapshot test with custom serialization', (t) => {
t.assert.snapshot({ value3: 3, value4: 4 }, {
serializers: [(value) => JSON.stringify(value)]
});
});
```snapshot(import prettyDOMprettyDOM(const component: anycomponent));
});
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should consume `foo` when provided', function () {
const const component: anycomponent = import renderrender(<import SomeComponentSomeComponent foo: stringfoo="bar" />).container.firstChild;
this.assert.snapshot(import prettyDOMprettyDOM(const component: anycomponent));
// `this` works only when `function` is used (not "fat arrow").
});
});
⚠️
assert.snapshotcomes from the test's context (torthis), notnode:assert. This is necessary because the test context has access to scope that is impossible fornode:assert(you would have to manually provide it every timeassert.snapshotis used, likesnapshot(this, value), which would be rather tedious).
Unit tests
Unit tests are the simplest tests and generally require relatively nothing special. The vast majority of your tests will likely be unit tests, so it is important to keep this setup minimal because a small decrease to setup performance will magnify and cascade.
import { function register<Data = any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<Data>): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register } from 'node:module';
import './setup.mjs'; // 💡
register<any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<any> | undefined): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register('some-plaintext-loader');
// plain-text files like graphql can now be imported:
// import GET_ME from 'get-me.gql'; GET_ME = '
import const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert from 'node:assert/strict';
import { function describe(name?: string, options?: it.TestOptions, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe, function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it } from 'node:test';
import { import CatCat } from './Cat.js';
import { import FishFish } from './Fish.js';
import { import PlasticPlastic } from './Plastic.js';
function describe(name?: string, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe('Cat', () => {
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should eat fish', () => {
const const cat: anycat = new import CatCat();
const const fish: anyfish = new import FishFish();
const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.doesNotThrow: (block: () => unknown, message?: string | Error) => void (+1 overload)Asserts that the function `fn` does not throw an error.
Using `assert.doesNotThrow()` is actually not useful because there
is no benefit in catching an error and then rethrowing it. Instead, consider
adding a comment next to the specific code path that should not throw and keep
error messages as expressive as possible.
When `assert.doesNotThrow()` is called, it will immediately call the `fn` function.
If an error is thrown and it is the same type as that specified by the `error` parameter, then an `AssertionError` is thrown. If the error is of a
different type, or if the `error` parameter is undefined, the error is
propagated back to the caller.
If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
[`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), or a validation
function. See
{@link
throws
}
for more details.
The following, for instance, will throw the `TypeError` because there is no
matching error type in the assertion:
```js
import assert from 'node:assert/strict';
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
SyntaxError,
);
```
However, the following will result in an `AssertionError` with the message
'Got unwanted exception...':
```js
import assert from 'node:assert/strict';
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
TypeError,
);
```
If an `AssertionError` is thrown and a value is provided for the `message` parameter, the value of `message` will be appended to the `AssertionError` message:
```js
import assert from 'node:assert/strict';
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
/Wrong value/,
'Whoops',
);
// Throws: AssertionError: Got unwanted exception: Whoops
```doesNotThrow(() => const cat: anycat.eat(const fish: anyfish));
});
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should NOT eat plastic', () => {
const const cat: anycat = new import CatCat();
const const plastic: anyplastic = new import PlasticPlastic();
const assert: Omit<typeof assert, "equal" | "notEqual" | "deepEqual" | "notDeepEqual" | "ok" | "strictEqual" | "deepStrictEqual" | "ifError" | "strict" | "AssertionError"> & {
...;
}
In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example,
{@link
deepEqual
}
will behave like
{@link
deepStrictEqual
}
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error
messages for objects display the objects, often truncated.
To use strict assertion mode:
```js
import { strict as assert } from 'node:assert';
import assert from 'node:assert/strict';
```
Example error diff:
```js
import { strict as assert } from 'node:assert';
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
```
To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS` environment variables. This will also
deactivate the colors in the REPL. For more on color support in terminal environments, read the tty
`getColorDepth()` documentation.assert.throws: (block: () => unknown, message?: string | Error) => void (+1 overload)Expects the function `fn` to throw an error.
If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
[`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), a validation function,
a validation object where each property will be tested for strict deep equality,
or an instance of error where each property will be tested for strict deep
equality including the non-enumerable `message` and `name` properties. When
using an object, it is also possible to use a regular expression, when
validating against a string property. See below for examples.
If specified, `message` will be appended to the message provided by the `AssertionError` if the `fn` call fails to throw or in case the error validation
fails.
Custom validation object/error instance:
```js
import assert from 'node:assert/strict';
const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
nested: true,
baz: 'text',
};
err.reg = /abc/i;
assert.throws(
() => {
throw err;
},
{
name: 'TypeError',
message: 'Wrong value',
info: {
nested: true,
baz: 'text',
},
// Only properties on the validation object will be tested for.
// Using nested objects requires all properties to be present. Otherwise
// the validation is going to fail.
},
);
// Using regular expressions to validate error properties:
assert.throws(
() => {
throw err;
},
{
// The `name` and `message` properties are strings and using regular
// expressions on those will match against the string. If they fail, an
// error is thrown.
name: /^TypeError$/,
message: /Wrong/,
foo: 'bar',
info: {
nested: true,
// It is not possible to use regular expressions for nested properties!
baz: 'text',
},
// The `reg` property contains a regular expression and only if the
// validation object contains an identical regular expression, it is going
// to pass.
reg: /abc/i,
},
);
// Fails due to the different `message` and `name` properties:
assert.throws(
() => {
const otherErr = new Error('Not found');
// Copy all enumerable properties from `err` to `otherErr`.
for (const [key, value] of Object.entries(err)) {
otherErr[key] = value;
}
throw otherErr;
},
// The error's `message` and `name` properties will also be checked when using
// an error as validation object.
err,
);
```
Validate instanceof using constructor:
```js
import assert from 'node:assert/strict';
assert.throws(
() => {
throw new Error('Wrong value');
},
Error,
);
```
Validate error message using [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions):
Using a regular expression runs `.toString` on the error object, and will
therefore also include the error name.
```js
import assert from 'node:assert/strict';
assert.throws(
() => {
throw new Error('Wrong value');
},
/^Error: Wrong value$/,
);
```
Custom error validation:
The function must return `true` to indicate all internal validations passed.
It will otherwise fail with an `AssertionError`.
```js
import assert from 'node:assert/strict';
assert.throws(
() => {
throw new Error('Wrong value');
},
(err) => {
assert(err instanceof Error);
assert(/value/.test(err));
// Avoid returning anything from validation functions besides `true`.
// Otherwise, it's not clear what part of the validation failed. Instead,
// throw an error about the specific validation that failed (as done in this
// example) and add as much helpful debugging information to that error as
// possible.
return true;
},
'unexpected error',
);
```
`error` cannot be a string. If a string is provided as the second
argument, then `error` is assumed to be omitted and the string will be used for `message` instead. This can lead to easy-to-miss mistakes. Using the same
message as the thrown error message is going to result in an `ERR_AMBIGUOUS_ARGUMENT` error. Please read the example below carefully if using
a string as the second argument gets considered:
```js
import assert from 'node:assert/strict';
function throwingFirst() {
throw new Error('First');
}
function throwingSecond() {
throw new Error('Second');
}
function notThrowing() {}
// The second argument is a string and the input function threw an Error.
// The first case will not throw as it does not match for the error message
// thrown by the input function!
assert.throws(throwingFirst, 'Second');
// In the next example the message has no benefit over the message from the
// error and since it is not clear if the user intended to actually match
// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]
// The string is only used (as message) in case the function does not throw:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second
// If it was intended to match for the error message do this instead:
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);
// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]
```
Due to the confusing error-prone notation, avoid a string as the second
argument.throws(() => const cat: anycat.eat(const plastic: anyplastic));
});
});
User Interface tests
UI tests generally require a DOM, and possibly other browser-specific APIs (such as IndexedDb used below). These tend to be very complicated and expensive to setup.
If you use an API like IndexedDb but it's very isolated, a global mock like below is perhaps not the way to go. Instead, perhaps move this beforeEach into the specific test where IndexedDb will be accessed. Note that if the module accessing IndexedDb (or whatever) is itself widely accessed, either mock that module (probably the better option), or do keep this here.
import { function register<Data = any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<Data>): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register } from 'node:module';
// ⚠️ Ensure only 1 instance of JSDom is instantiated; multiples will lead to many 🤬
import import jsdomjsdom from 'global-jsdom';
import './setup.units.mjs'; // 💡
import { import IndexedDbIndexedDb } from './globals/IndexedDb.js';
register<any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<any> | undefined): void (+1 overload)Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
[Customization hooks](https://nodejs.org/docs/latest-v22.x/api/module.html#customization-hooks).
This feature requires `--allow-worker` if used with the
[Permission Model](https://nodejs.org/docs/latest-v22.x/api/permissions.html#permission-model).register('some-css-modules-loader');
import jsdomjsdom(var undefinedundefined, {
url: stringurl: 'https://test.example.com', // ⚠️ Failing to specify this will likely lead to many 🤬
});
// Example of how to decorate a global.
// JSDOM's `history` does not handle navigation; the following handles most cases.
const const pushState: (data: any, unused: string, url?: string | URL | null) => voidpushState = module globalThisglobalThis.module history
var history: History
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/history)history.History.pushState(data: any, unused: string, url?: string | URL | null): void[MDN Reference](https://developer.mozilla.org/docs/Web/API/History/pushState)pushState.CallableFunction.bind<(data: any, unused: string, url?: string | URL | null) => void>(this: (data: any, unused: string, url?: string | URL | null) => void, thisArg: unknown): (data: any, unused: string, url?: string | URL | null) => void (+1 overload)For a given function, creates a bound function that has the same body as the original function.
The this object of the bound function is associated with the specified object, and has the specified initial parameters.bind(module globalThisglobalThis.module history
var history: History
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/history)history);
module globalThisglobalThis.module history
var history: History
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/history)history.History.pushState(data: any, unused: string, url?: string | URL | null): void[MDN Reference](https://developer.mozilla.org/docs/Web/API/History/pushState)pushState = function function (local function) mock_pushState(data: any, unused: any, url: any): voidmock_pushState(data: anydata, unused: anyunused, url: anyurl) {
const pushState: (data: any, unused: string, url?: string | URL | null) => void[MDN Reference](https://developer.mozilla.org/docs/Web/API/History/pushState)pushState(data: anydata, unused: anyunused, url: anyurl);
module globalThisglobalThis.var location: Location[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/location)location.Location.assign(url: string | URL): voidNavigates to the given URL.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Location/assign)assign(url: anyurl);
};
beforeEach(function globalUIBeforeEach(): voidglobalUIBeforeEach);
function function globalUIBeforeEach(): voidglobalUIBeforeEach() {
module globalThisglobalThis.indexedDb = new import IndexedDbIndexedDb();
}
You can have 2 different levels of UI tests: a unit-like (wherein externals & dependencies are mocked) and a more end-to-end (where only externals like IndexedDb are mocked but the rest of the chain is real). The former is generally the purer option, and the latter is generally deferred to a fully end-to-end automated usability test via something like Playwright or Puppeteer. Below is an example of the former.
import { function before(fn?: it.HookFn, options?: it.HookOptions): voidThis function creates a hook that runs before executing a suite.
```js
describe('tests', async () => {
before(() => console.log('about to run some test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
```before, function describe(name?: string, options?: it.TestOptions, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe, const mock: it.MockTrackermock, function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it } from 'node:test';
import { import screenscreen } from '@testing-library/dom';
import { import renderrender } from '@testing-library/react'; // Any framework (ex svelte)
// ⚠️ Note that SomeOtherComponent is NOT a static import;
// this is necessary in order to facilitate mocking its own imports.
function describe(name?: string, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe('<SomeOtherComponent>', () => {
let let SomeOtherComponent: anySomeOtherComponent;
let let calcSomeValue: anycalcSomeValue;
function before(fn?: it.HookFn, options?: it.HookOptions): voidThis function creates a hook that runs before executing a suite.
```js
describe('tests', async () => {
before(() => console.log('about to run some test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
```before(async () => {
// ⚠️ Sequence matters: the mock must be set up BEFORE its consumer is imported.
// Requires the `--experimental-test-module-mocks` be set.
let calcSomeValue: anycalcSomeValue = const mock: it.MockTrackermock.test.MockTracker.module(specifier: string, options?: it.MockModuleOptions): it.MockModuleContextThis function is used to mock the exports of ECMAScript modules, CommonJS modules, and Node.js builtin modules.
Any references to the original module prior to mocking are not impacted.
Only available through the [--experimental-test-module-mocks](https://nodejs.org/api/cli.html#--experimental-test-module-mocks) flag.module('./calcSomeValue.js', {
calcSomeValue: it.Mock<(...args: any[]) => undefined>calcSomeValue: const mock: it.MockTrackermock.test.MockTracker.fn<(...args: any[]) => undefined>(original?: ((...args: any[]) => undefined) | undefined, options?: it.MockFunctionOptions): it.Mock<(...args: any[]) => undefined> (+1 overload)This function is used to create a mock function.
The following example creates a mock function that increments a counter by one
on each invocation. The `times` option is used to modify the mock behavior such
that the first two invocations add two to the counter instead of one.
```js
test('mocks a counting function', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 });
assert.strictEqual(fn(), 2);
assert.strictEqual(fn(), 4);
assert.strictEqual(fn(), 5);
assert.strictEqual(fn(), 6);
});
```fn(),
});
({ type SomeOtherComponent: anySomeOtherComponent } = await import('./SomeOtherComponent.jsx'));
});
function describe(name?: string, fn?: it.SuiteFn): Promise<void> (+3 overloads)The `suite()` function is imported from the `node:test` module.describe('when calcSomeValue fails', () => {
// This you would not want to handle with a snapshot because that would be brittle:
// When inconsequential updates are made to the error message,
// the snapshot test would erroneously fail
// (and the snapshot would need to be updated for no real value).
function it(name?: string, fn?: it.TestFn): Promise<void> (+3 overloads)The `test()` function is the value imported from the `test` module. Each
invocation of this function results in reporting the test to the `TestsStream`.
The `TestContext` object passed to the `fn` argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
`test()` returns a `Promise` that fulfills once the test completes.
if `test()` is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
```js
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
```
The `timeout` option can be used to fail the test if it takes longer than `timeout` milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.it('should fail gracefully by displaying a pretty error', () => {
let calcSomeValue: anycalcSomeValue.mockImplementation(function function (local function) mock__calcSomeValue(): nullmock__calcSomeValue() {
return null;
});
import renderrender(<let SomeOtherComponent: anySomeOtherComponent />);
const const errorMessage: anyerrorMessage = import screenscreen.queryByText('unable');
assert.ok(const errorMessage: anyerrorMessage);
});
});
});