Onboarding Engineers Into an Existing Test Suite

A mature test suite encodes years of decisions that are invisible to a newcomer: why this check lives at the unit tier, why that fixture must not be edited, why the end-to-end suite has exactly nine tests. Without a guided path, new engineers reach the obvious conclusions — write an end-to-end test for the feature, copy the nearest fixture, add a sleep when something is timing-dependent — and the suite degrades one reasonable decision at a time. This guide covers what a first day, first week and first month of testing onboarding should contain, and which documents are worth maintaining for it. It sits under test ownership models.

Root Cause Analysis

Test suites are unusually hostile to newcomers for a structural reason: the conventions are implicit and the feedback is delayed. Application code has types, linting and a reviewer who knows the domain; a test that follows none of the local conventions still passes, so nothing objects until months later when it becomes flaky or blocks a refactor.

The second problem is that the reasoning behind a suite’s shape is rarely written down. A newcomer sees nine end-to-end tests and cannot tell whether that is a deliberate ceiling or a gap waiting to be filled. Without that context, the helpful instinct — add coverage — pushes directly against a decision the team made carefully.

The third is the first-run experience. If a new engineer’s first attempt at running the suite produces a confusing error — a missing fixture, an unset variable, a container that will not start — they learn that the tests are somebody else’s problem, and that impression is remarkably durable.

Why test conventions are harder to learn than code conventions Application code gives immediate feedback through types, linting and review, while a test that ignores every local convention still passes, so the feedback arrives months later as flakiness or friction. application code types reject mistakes lint rules flag style reviewers know the domain feedback in minutes test code a wrong-tier test still passes a sleep still passes a duplicate still passes feedback in months, as flakiness
Nothing in the toolchain objects to a badly-shaped test, so the conventions have to be taught explicitly.

Reproducible Setup

Make the first run work from a clean checkout with one command. Everything else in onboarding depends on this.

// package.json
{
  "scripts": {
    "setup": "npm ci && tsx scripts/fixtures/fetch.ts && playwright install --with-deps chromium",
    "test": "vitest run",
    "test:e2e": "playwright test",
    "test:watch": "vitest"
  }
}
git clone "$REPO" && cd "$REPO"
npm run setup && npm test
# ✓ 612 tests passed (38.4s)

If that sequence does not work on a clean machine, fix it before writing any documentation — the documentation will otherwise spend its first page apologising.

Implementation

Step 1 — Write a one-page map of the suite. Not how to write tests, but where things are and why: the tiers, what each is for, and the count you deliberately keep at each.

<!-- docs/TEST-MAP.md -->
| Tier | Where | Count | Runs in | What it is for |
| --- | --- | --- | --- | --- |
| unit | `src/**/*.test.ts` | ~540 | pull request | pure logic: pricing, permissions, validation |
| component | `src/**/*.test.tsx` | ~180 | pull request | rendering and interaction, jsdom |
| end-to-end | `e2e/journeys/**` | 9 | pull request | the journeys we cannot ship broken |
| visual | `e2e/visual/**` | 24 | nightly | rendering regressions, not behaviour |

The end-to-end count is a ceiling, not a target. Adding one means removing one
or explaining why in the description.

Step 2 — Give a guided first task that teaches conventions by doing. A prepared task — fix a deliberately weak test, or add a case to a well-shaped file — teaches more in an hour than a document does in a week.

<!-- docs/onboarding/first-task.md -->
1. Run `npm test src/domain/pricing` and read `pricing.test.ts` — this is the
   shape we aim for: builders for setup, one behaviour per test, exact values.
2. `src/domain/shipping.test.ts` has a weak test; find it with
   `npx stryker run --mutate "src/domain/shipping.ts"` and read the survivor.
3. Strengthen that assertion, re-run, and confirm the mutant is killed.
4. Open a pull request. A reviewer will walk through the conventions with you.

Step 3 — Write down the decisions that look like gaps. This is the document that prevents the most damage, and it is usually the one nobody has written.

<!-- docs/TEST-DECISIONS.md -->
- We keep 9 end-to-end tests deliberately. See the cost analysis in the
  handbook; adding a tenth needs a reason in the description.
- We do not snapshot-test components. Snapshots were removed in 2025 after they
  were updated reflexively for a year without anyone reading the diffs.
- `test/fixtures/catalogue.json` is generated. Edit the generator, not the file.
- We do not mock the database in integration tests; we use a real one per worker.

Step 4 — Pair on the first real test rather than reviewing it. A review catches what is wrong; pairing conveys why, and it takes less total time than three rounds of review comments.

Step 5 — Make the conventions discoverable from the code. A newcomer reads code far more than documentation, so the best-shaped file in each tier should be easy to find and explicitly marked as the reference.

/**
 * Reference example for unit tests in this repository.
 * - builders for setup, never shared fixture objects
 * - one behaviour per test, named as a sentence
 * - exact expected values, not recomputed expressions
 * See docs/TEST-MAP.md for the tier map.
 */
import { describe, test, expect } from 'vitest';
What to cover in the first day, week and month Day one is a working first run and the tier map, the first week is a guided task and a paired real test, and the first month is exposure to triage and to the health review where the reasoning is revisited. day one one-command setup works reads the tier map runs the suite green first week the guided task pairs on a real test reads the decisions page first month triages a real failure attends the health review questions one decision
The last item matters most: a newcomer questioning a decision is how the documented reasoning stays honest.

Step 6 — Let the newcomer improve the onboarding. Their confusion is the only accurate measure of where the documentation is wrong, and it expires within about a month.

Verification

Verify the setup path on a genuinely clean machine, not on one that already has caches, a global toolchain and the right Node version. A container is the honest test.

docker run --rm -it -v "$PWD:/repo" -w /repo node:20 bash -lc \
  'npm run setup && npm test'
# if this needs a manual step, the documentation is already wrong

Then verify the conventions are being learned by looking at output rather than asking. Review the first three test files a new engineer wrote against the reference file; recurring differences point at a gap in the documentation rather than at the person.

Finally, verify the documents are current, which is where onboarding material usually fails. A test-map table claiming nine end-to-end tests when there are nineteen is worse than no table, because it teaches something false with authority.

echo "e2e specs: $(find e2e/journeys -name '*.spec.ts' | wc -l)"
grep -oE '\| [0-9]+ \|' docs/TEST-MAP.md
# keep these in step, or generate the table
Three documents worth maintaining, and one to avoid A tier map, a decisions page and a guided first task each earn their maintenance, while a comprehensive testing handbook goes stale and is not read. tier map where things are one table decisions why the gaps are deliberate first task learn by doing one hour handbook thirty pages stale, unread
Three short documents that are true beat one long one that used to be.

Troubleshooting

Symptom: new engineers keep writing end-to-end tests for everything. Diagnosis: the tier map exists but the reasoning does not, so the ceiling looks arbitrary. Fix: put the cost figures in the decisions page — a number from measuring the running cost of a test suite settles the question faster than any amount of principle.

Symptom: the first run fails on a new machine every time. Diagnosis: setup depends on state that accumulated on existing machines — a global tool, an environment variable in someone’s profile. Fix: run the container check from the verification step in CI weekly, so the setup path is tested rather than assumed.

Symptom: conventions are learned, then drift within a quarter. Diagnosis: the reference file has changed, or the team’s practice has moved and the documentation has not. Fix: review the onboarding documents at the same cadence as the health review; they are as much a shared artifact as the policy.

Symptom: onboarding takes a whole week of someone’s time. Diagnosis: it is being delivered as a lecture rather than as a guided task with a pairing session. Fix: invert it — an hour of preparation, an hour of pairing, and the rest learned by doing with review; the documents exist so the explanation does not have to be repeated.

FAQ

How much testing onboarding is enough?

A working first run, a one-page map, and one guided task with a pairing session — perhaps three hours in total. Beyond that the returns fall off quickly, because conventions are learned by writing tests and receiving feedback rather than by reading about them.

Should onboarding cover the tooling or the philosophy?

Both, but the philosophy is what a newcomer cannot infer. Tooling is discoverable from the scripts and the configuration; the reason the end-to-end suite is small, or why snapshots were removed, exists only in the team’s memory unless someone writes it down.

Who should own the onboarding material?

The same person or team that owns the testing policy, since the two documents constantly reference each other. Keeping them together also means a change to the policy prompts a look at the onboarding, which is exactly when it is most likely to go stale.

What about contractors or short-term contributors?

The same path, compressed, and with more emphasis on the decisions page — a short-term contributor has less time to absorb conventions by osmosis and is more likely to reach the plausible-but-wrong conclusions the page exists to prevent.