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:
- The pure logic is tested. Counting, formatting, time-zone math — these are functions with no DOM, so they are trivial to test exhaustively.
- 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
Notes from building a small toolbox: tools compound search traffic faster than articles, if you pick the right ones.
What Base64 is, why Chinese text sometimes breaks, and how to encode or decode it without losing characters.