~3 min read • Updated Dec 30, 2025
1. Importing the Module
const test = require('node:test');
// or ESM
import test from 'node:test';
2. Basic Test Types
The test runner supports all major styles of testing:
2.1 Synchronous Tests
test('Synchronous passing test', (t) => {
assert.strictEqual(1, 1);
});
test('Synchronous failing test', (t) => {
assert.strictEqual(1, 2);
});
2.2 Async & Promise Tests
test('Async passing test', async (t) => {
assert.strictEqual(1, 1);
});
test('Async failing test', async (t) => {
throw new Error('failed');
});
test('Promise failing test', (t) => {
return Promise.reject(new Error('failed'));
});
2.3 Callback Tests
test('Callback passing test', (t, done) => {
setImmediate(done);
});
test('Callback failing test', (t, done) => {
setImmediate(() => done(new Error('failed')));
});
If any test fails, Node.js exits with code 1.
3. Subtests
Subtests allow grouping and structuring test suites:
test('Top level test', async (t) => {
await t.test('Subtest 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('Subtest 2', (t) => {
assert.strictEqual(2, 2);
});
});
4. Skipping & TODO Tests
test('Skipped test', { skip: true }, (t) => {});
test('Skipped with reason', { skip: 'reason' }, (t) => {});
test('TODO test', { todo: true }, (t) => {
throw new Error('ignored failure');
});
// Inside a test:
t.skip('skip inside test');
t.todo('todo inside');
5. Only Tests
Run only specific tests:
test('Only this runs', { only: true }, (t) => {});
CLI:
node --test-only
Inside subtests:
t.runOnly(true);
6. Hooks
Hooks allow setup and teardown logic:
test('With hooks', async (t) => {
t.before(() => console.log('Before all'));
t.beforeEach(() => console.log('Before each'));
t.afterEach(() => console.log('After each'));
t.after(() => console.log('After all'));
await t.test('Subtest 1', () => {});
await t.test('Subtest 2', () => {});
});
7. Mocking
7.1 Mocking Functions
test('Mock function', (t) => {
const fn = t.mock.fn((a, b) => a + b);
assert.strictEqual(fn(2, 3), 5);
assert.strictEqual(fn.mock.callCount(), 1);
});
7.2 Mocking Methods
test('Mock method', (t) => {
const obj = { add: (a, b) => a + b };
t.mock.method(obj, 'add');
obj.add(1, 2);
assert.strictEqual(obj.add.mock.callCount(), 1);
});
7.3 Mocking Timers & Date
test('Mock timers', (t) => {
t.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
setTimeout(() => console.log('done'), 1000);
t.mock.timers.tick(1000);
});
8. Snapshot Testing
test('Snapshot', (t) => {
t.assert.snapshot({ a: 1, b: [2, 3] });
});
Update snapshots:
node --test-update-snapshots
9. Coverage
node --experimental-test-coverage --test-reporter=lcov
10. Watch Mode
node --test --watch
11. Custom Reporters
node --test --test-reporter=./my-reporter.js
12. Running Tests
node --test # run all tests
node --test test/**/*.test.js # pattern
node --test-only # only { only: true }
node --test-name-pattern="my test" # filter by name
Conclusion
The node:test module is a powerful, built‑in test runner offering:
- Simple and expressive API
- Subtests and hooks
- Mocking for functions, methods, timers, and modules
- Snapshot testing
- Coverage and watch mode
- Custom reporters
- Strict mode and test plans
It is a complete, modern testing solution for Node.js — with zero external dependencies.
Written & researched by Dr. Shahin Siami