/ #node #testing 

Node.js Native Test Runner

If anyone missed it, Node.js 18 includes a test runner/test definition module (node --test and node:test respectively).

node:test exports a test function and you can run the Node CLI with a --test flag which does some basic search/matching for test files.

Full Documentation: nodejs.org/api/test.html

Table of Contents

Example Node.js Tests with Assertions

The recommended way to do assertions is to use the existing assert module.

Combination of node:test + node:assert/strict are good for testing pure code (ie. check output is as expected).

For module interception or advanced stubbing, you’ll have to look elsewhere, although I did find CallTracker the other day, which isn’t as complete as jest.fn() or sinon stubs but you can create a stub that reports on how many times it’s been called, see assert.CallTracker docs.

In short: you can write and run tests in Node.js without any npm packages.

A simple example, in a ping.mjs file.

import test from 'node:test';
import assert from 'node:assert/strict';
const ping = () => 'pong';

test('ping', (_t) => {
  assert.equal(ping(), 'pong');
});

We can run the above using node --test ping.mjs or node ping.mjs which gives the following output:

node ping.mjs 
(node:2191) ExperimentalWarning: The test runner is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
TAP version 13
ok 1 - ping
  ---
  duration_ms: 0.001783726
  ...
1..1
# tests 1
# pass 1
# fail 0
# skipped 0
# todo 0
# duration_ms 0.91425132

Given a failure by changing assert.equal(ping(), 'pong'); to assert.equal(ping(), 'ping');, we would get the following output:

node ping.mjs
(node:2321) ExperimentalWarning: The test runner is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
TAP version 13
not ok 1 - ping
  ---
  duration_ms: 0.00915903
  failureType: 'testCodeFailure'
  error: |-
    Expected values to be strictly equal:
    
    'pong' !== 'ping'
    
  code: 'ERR_ASSERTION'
  stack: |-
    TestContext.<anonymous> (ping.mjs:5:10)
    Test.runInAsyncScope (node:async_hooks:202:9)
    Test.run (node:internal/test_runner/test:340:20)
    Test.start (node:internal/test_runner/test:292:17)
    Test.test (node:internal/test_runner/harness:126:18)
    file://ping.mjs:5:1
    ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    async Promise.all (index 0)
    async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    async loadESM (node:internal/process/esm_loader:85:5)
  ...
1..1
# tests 1
# pass 0
# fail 1
# skipped 0
# todo 0
# duration_ms 0.684553003

See more examples at github.com/HugoDF/microbundle-ts-pkg/tree/master/test

For more advanced functionality to augment your tests:

Notes on node:test TAP output

Back to the Node.js test runner, it outputs in TAP, which is the “test anything protocol”, here’s the specification: testanything.org/tap-specification.html.

That means you can take your output and pipe it into existing formatters and there was already node-tap as a userland runner implementation.

Closing remarks

Final couple of things, which are a given for most modern Node.js test runners:

  • it supports all the usual test function formats ie. Promise rejection, error throwing, done callback not invoked are all reported as failures
  • there’s “skip/only” and “sub-tests/test suite” concepts

Node.js “test” files that use node:test can be run directly using node file.js for example. node --test <more-options> can be used for running multiple files at once, see “test runner execution model”.

Photo by DiEGO MüLLER on Unsplash

Author

Hugo Di Francesco

Co-author of "Professional JavaScript", "Front-End Development Projects with Vue.js" with Packt, "The Jest Handbook" (self-published). Hugo runs the Code with Hugo website helping over 100,000 developers every month and holds an MEng in Mathematical Computation from University College London (UCL). He has used JavaScript extensively to create scalable and performant platforms at companies such as Canon, Elsevier and (currently) Eurostar.

Get The Jest Handbook (100 pages)

Take your JavaScript testing to the next level by learning the ins and outs of Jest, the top JavaScript testing library.