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.
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';
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
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.
Related
- Back to Test Ownership Models
- Writing a testing policy a team will follow — the rules onboarding introduces.
- Running a test health review cadence — where the decisions get revisited.
- Unit vs Integration vs E2E Mapping — the reasoning behind the tier map.