← All posts
1 min read

Every tool ships with its tests

How a solo builder keeps small utilities reliable without slowing down, by testing pure logic and key interactions.

A small toolbox can rot quickly. One refactor changes a regex, and the text counter silently breaks on Chinese input. The only defense that scales for a solo developer is tests that run on every change.

Two layers, not five

I do not chase coverage percentages. I want two things to be true for each tool:

  1. The pure logic is tested. Counting, formatting, time-zone math — these are functions with no DOM, so they are trivial to test exhaustively.
  2. The main interaction is tested. Type something, click Format, see a result, click Copy. These tests catch the wiring mistakes that logic tests miss.
it("updates counts as the user types", () => {
  fireEvent.change(input, { target: { value: "Hello world" } });
  expect(statValue("Words")).toBe("2");
});

What is deliberately not unit-tested

Some behavior cannot run in a headless DOM. Real canvas image compression, real QR rendering, real browser time-zone data. For those I keep the testable math in pure functions and verify the rest in a real browser.

This is not a shortcut. It is an honest boundary: test what is deterministic, and confirm the rest where it actually runs.

The payoff

When I add the fifth tool, I do not re-read the first four to make sure I did not break them. I run npm test. If it is green, I move on. That compounding confidence is the whole point.

Related