A snapshot assertion compares a value against the last approved version of itself, stored in a file next to the test. It suits output whose exact shape matters but is tedious to write out: a rendered receipt, a generated SQL string, a serialized response. It has been stable since Node 23.4.0.
test('the receipt layout is stable', (t) => {
t.assert.snapshot(receipt([{ name: 'Mug', price: 8, qty: 2 },
{ name: 'Tea', price: 5, qty: 1 }]));
});
// test/snapshot.test.js.snapshot, written by --test-update-snapshots
exports[`the receipt layout is stable 1`] = `
"2 x Mug @ 8\\n1 x Tea @ 5\\nTOTAL 21"
`;The first run has nothing to compare against and fails on purpose with ERR_INVALID_STATE: Cannot read snapshot file ... Missing snapshots can be generated by rerunning the command with the --test-update-snapshots flag. Run it with that flag and the runner writes the file. Its key is the test name plus a counter, and the file is committed to version control — it is the approved output. t.assert.fileSnapshot(value, path) writes one snapshot per file instead.
Values are serialized with util.inspect. Pass your own serializers, applied in order, to strip the parts that legitimately change — here every createdAt becomes "<date>":
import { snapshot } from 'node:test';
snapshot.setDefaultSnapshotSerializers([
(value) => JSON.stringify(value, (k, v) => (k === 'createdAt' ? '<date>' : v), 2),
]);Snapshots are a sharp tool: regenerating them is one flag away, which makes it easy to approve a regression without reading it, and a snapshot of a whole HTTP response tells you that something changed but not what should be true. Keep each small enough to read in a diff, and regenerate one path at a time.