Think of this as a light introduction to testing JavaScript – what deserves a test, how to run a few assertions, and habits that pay off before you adopt a full test stack.
What to test first
- Pure functions – formatting, validation helpers, reducers with no DOM.
- Edge cases you have already broken once – empty arrays, bad API payloads.
- Bug fixes – write a test that fails without the fix, then pass it.
Do not start by testing every click handler. Test logic that would hurt if it regressed silently.
A tiny assertion helper
function assert(condition, message) {
if (!condition) throw new Error(message ?? 'Assertion failed');
}
function assertEqual(actual, expected) {
assert(actual === expected, `Expected ${expected}, got ${actual}`);
}
Testing a pure function
function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
assertEqual(clamp(5, 0, 10), 5);
assertEqual(clamp(-1, 0, 10), 0);
assertEqual(clamp(99, 0, 10), 10);
Run with Node: node tests/clamp.test.js. In the browser, import the helper and functions in a test page or use devtools.
Node’s built-in test runner
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { clamp } from './clamp.js';
test('clamp keeps value in range', () => {
assert.equal(clamp(5, 0, 10), 5);
assert.equal(clamp(-1, 0, 10), 0);
});
Run with node --test. No extra install for small modules. Vitest and Jest add DOM mocks and watch mode when projects grow.
DOM tests
For UI behaviour, consider Testing Library style tests – render HTML, simulate user events, assert on visible text. That is easier to maintain than asserting on class names. For these tutorials, keep DOM tests few; focus on extractable logic.
Manual checklist still counts
Not everything needs automation early. A short checklist before deploy – keyboard nav, form errors, slow network in devtools – catches issues cheaply. Tests complement manual checks; they do not replace thinking.
Next: tooling overview – npm scripts, dev servers, and why bundlers exist.

