1export function discount(price, percent) {2 const off = price * percent / 100;3 return price - off; return Math.max(0, price - off);4}node --testactual–expected–result–1import test from "node:test";2import assert from "node:assert/strict";3import { discount } from "./price.js";4test("10% off 50 is 45", () => {5 assert.equal(discount(50, 10), 45);6});7test("never below 0", () => {8 assert.equal(discount(50, 150), 0);9});$ node --test✔ 10% off 50 is 45✖ never below 0ℹ pass 1 ℹ fail 1exit code 145-250AssertionError
Right: the test runner and the assertion (actual, expected, result)Left: price.js and price.test.js; front: the terminalTokens: calls, returned values, a pass check and the thrown AssertionErrorBack left, price.js, the code under test; in front of it, price.test.js with two tests. On the right, the test runner node --test and the assertion (actual, expected, result); in front, the terminal with the report. A test passes when its function returns and fails when it throws: the second assertion throws an AssertionError, so the run ends with exit code 1 until line 3 is fixed. The terminal shows the spec reporter's lines without the timings, with the pass and fail counts side by side (Node prints them on separate lines), plus the exit code. The full report also counts suites, skipped and cancelled tests, and prints the error with its stack.

What a test is

  1. A unit test is a small program that calls one piece of your code, a unit, with inputs whose right answer you already know. It checks the answer automatically, so you can rerun every check after every change.

The test file and the runner

A passing test

A failing test

Fix and run again

What happens

// step 1/11 · why
unit        one small piece of code, here a function
test        call it with known input
assertion   check the result; throw if it is wrong
runner      run every test, report pass or fail

node:assert/strict is the strict mode of node:assert: assert.equal there is assert.strictEqual. The lesson says it compares with ===; precisely, it uses Object.is(), which works like === except that NaN equals NaN and 0 differs from -0 (so assert.strictEqual(NaN, NaN) passes and assert.strictEqual(0, -0) throws). For arrays and objects use assert.deepEqual (deepStrictEqual), which compares contents instead of identity. The three files are real. Put price.js, price.test.js and a package.json with "type": "module" in one folder and run node --test (Node.js 20 or newer).