The assert Module

node:test has no expectation language of its own; assertions come from node:assert. Import the strict variant — node:assert/strict — and never the legacy default, whose equal uses == and whose deepEqual ignores prototypes, so '11' and 11 compare equal. In strict mode equal is Object.is-based, deepEqual is deepStrictEqual, and failures print the diff you just saw.

The assertions worth knowing in node:assert
Assertion Use it for
equal, notEqual primitives and identity
deepEqual, notDeepEqual whole objects and arrays
partialDeepStrictEqual an object with fields you do not control
ok(value) a truthy check; prints the source expression
match, doesNotMatch a string against a regular expression
throws, rejects sync and async error paths

partialDeepStrictEqual (Node 23.4.0, stable since 24.0.0) passes as long as the expected object is a subset of the actual one, which is what you want for an API response carrying an _id and a timestamp. assert.CallTracker went the other way, runtime-deprecated in Node 23 and removed in Node 24; use the mocking API in Mocking.

assert.throws takes the function itself, not its result, plus a second argument narrowing what may be thrown; assert.rejects is the same for promises and must be awaited. The context carries these as t.assert.*, which makes each assertion count toward the test's plan:

Error assertions and a declared assertion countJavaScript
assert.throws(() => applyCoupon(30, 'NOPE'), {
  name: 'Error', message: 'Unknown coupon: NOPE',
});
await assert.rejects(loadProduct('missing'), { code: 'ERR_NOT_FOUND' });
test('coupon rules', (t) => {
  t.plan(2);
  t.assert.equal(applyCoupon(30, 'HALF'), 15);
  t.assert.throws(() => applyCoupon(30, 'NOPE'), /Unknown coupon/);
});

A regular expression matches the message, an object compares the listed properties only, and a function may assert on anything but must return true. Forgetting await on assert.rejects writes a test that can never fail. t.plan(n) declares how many assertions must run, so a callback that silently never fires fails the test — the standard defense for event-driven code.