Debug code
Write a regression test
Capture the smallest failing input as a test, see it fail, apply the repair, and keep the test permanently.
10 minute lesson
A fix without a test is temporary. A regression test proves the old behavior is present before the fix and prevents the same failure from returning unnoticed. It is also the cheapest artifact to produce right now: the minimal failing case from your reduction work is the test input.
Fail first
The order is what makes it a regression test. Write it, watch it fail, then fix.
Express the expected behavior:
import assert from 'node:assert/strict'
import test from 'node:test'
test('empty cart totals zero', () => {
assert.equal(total([]), 0)
})
Run the test before the code change:
node --test cart.test.mjs
# ✖ empty cart totals zero
# AssertionError: Expected 0, got NaN
That failing run is evidence the test actually exercises the bug. Now apply the repair and run again. The pass means the fix works, and the red-to-green transition means the test guards the right thing.
Skip the failing run and you risk a test that passes for the wrong reason: it calls a different code path, or its assertion is too loose to catch anything. A test that never failed proves nothing.
Assert the contract, not the bug
Do not write a test that passes because it reproduces the bug’s wrong result. assert.equal(total([]), NaN) would pass against today’s broken code and permanently enshrine the failure. Ask what the function should do — the intended contract — and assert that.
Name the test after the behavior, not the ticket. 'empty cart totals zero' tells the next reader what is protected. 'fixes bug #4521' tells them to go read a ticket that may not exist anymore.
Keep it, and keep it small
Add a nearby edge case only when it protects a distinct boundary. An item with a missing price is a different contract than an empty cart, so it earns its own test. Resist adding ten speculative cases; each one you write now is one somebody maintains forever.
The test stays in the suite permanently. Six months from now someone refactors total(), and this test is the only thing standing between them and reintroducing your bug.
Lesson completed