All cheatsheets

Cheatsheets

Testing strategy

Test levels, the pyramid vs the trophy, doubles, flaky-test fixes, and Vitest & Playwright.

Visualize

Testing — the pyramid & the TDD loop

Many fast unit tests at the base, few slow E2E at the top — plus the red → green → refactor loop.

↑ fewer · slower · costlier
E2Efew · slow · $$$
Integrationsome · medium · $$
Unitmany · fast · $
many · fast · cheap ↓
expect(add(2, 3)).toBe(5)  // ✗ fails

Write a failing test first — it defines the goal.

Lean on the base: many fast unit tests, fewer slow E2E. Each is written red → green → refactor.

68 entries

Test levels5

Unit test

Tests one function/module in isolation, dependencies stubbed.

Integration test

Tests several real units together (e.g. service + DB + parser).

E2E (end-to-end) test

Drives the whole app like a user — browser, server, DB.

Contract test

Verifies a producer and consumer agree on an API/message shape.

Speed vs confidence

Lower tests = faster, cheaper, less realistic; higher = slower, more confident.

Strategy & shape4

Test Pyramid

Many unit, fewer integration, very few e2e (Mike Cohn).

Testing Trophy

static → unit → integration (most) → e2e (Kent C. Dodds).

Why integration wins on ROI

Integration tests resemble how software is used, with manageable cost.

Ice-cream cone (anti-pattern)

Inverted pyramid: lots of manual + e2e, few unit tests.

Test doubles9

Test double (umbrella term)

Any stand-in for a real dependency: dummy, stub, spy, mock, or fake.

Dummy

A placeholder passed to satisfy a signature; never actually used.

Stub

Returns canned answers to calls made during the test.

Spy

Records how it was called (args, count) while optionally passing through.

Mock

A double with pre-programmed expectations; the assertion is on the interaction.

Fake

A working but simplified implementation (e.g. in-memory DB).

Mock vs fake

Mock = scripted calls + assertions; fake = a real (simpler) implementation.

Over-mocking (pitfall)

So many mocks the test asserts implementation, not behavior.

Classicist vs mockist

Classicist tests state with real objects; mockist tests interactions with mocks.

Structure & style8

Arrange-Act-Assert (AAA)

Three phases: set up, do the thing, check the result.

Given-When-Then

BDD phrasing of AAA: precondition, action, expected outcome.

One logical assertion per test

Each test verifies a single behavior, not a grab-bag of checks.

Descriptive test names

Name the behavior, not the method: 'returns 401 when token expired'.

Fixtures vs factories vs builders

Three ways to produce test data, trading reuse for clarity.

Test data management

Keep data minimal, intention-revealing, and isolated per test.

beforeEach / afterEach

Run setup before, and teardown after, every test in a block.

Test isolation

No test depends on another's state or execution order.

Vitest (runnable)10

describe / it / expect

Group tests, declare a case, assert on a value.

Common matchers

toBe / toEqual / toMatchObject / toThrow / resolves / rejects.

vi.fn()

Create a mock/spy function you control and assert on.

vi.spyOn(obj, "method")

Wrap an existing method to record calls (and optionally replace it).

vi.mock("./module")

Replace an entire imported module with a mock.

vi.useFakeTimers() + advanceTimersByTime

Take control of time so timers fire instantly and deterministically.

test.each([...])

Parameterised test — run the same body over a table of cases.

beforeEach (Vitest)

Reset state/mocks before every test for isolation.

vitest run --coverage

Run the suite once and report coverage (line/branch/function).

Full example test file

A small, complete Vitest file you can drop in and run.

Playwright (runnable)9

test / expect (@playwright/test)

Declare a browser test; assert with auto-retrying expect.

Locators: getByRole / getByText / getByTestId

Find elements the way a user (or assistive tech) would.

await expect(locator).toBeVisible()

Web-first assertion — auto-waits and retries until it passes or times out.

test.step("name", async () => {...})

Group actions into a named step for readable traces/reports.

page.route() — network mocking

Intercept requests and serve a canned response.

Fixtures (Playwright)

Reusable, isolated setup injected per test (page, context, custom).

Trace / screenshot on failure

Capture a replayable trace and screenshot when a test fails.

Parallelism & projects

Run tests in parallel and across multiple browser configs.

Full example e2e file

A small, complete Playwright spec you can drop in and run.

Coverage & quality4

Line vs branch vs statement coverage

Different things 'coverage %' can mean — branch is the strict one.

Coverage ≠ quality (Goodhart)

Code can be 100% covered and still be wrong — coverage measures execution, not correctness.

Mutation testing (Stryker)

Inject bugs ('mutants') and check your tests catch them — a real quality signal.

FIRST principles

Fast · Isolated · Repeatable · Self-validating · Timely.

Flaky tests10

Flaky test (definition)

A test that passes and fails on the SAME code without changes — non-deterministic.

Async not awaited

Cause: the test finishes before the async work settles.

Time / Date.now()

Cause: real clocks make tests time-of-day or timezone dependent.

Randomness

Cause: Math.random / uuid / shuffles make outcomes vary run to run.

Test order / shared state

Cause: one test leaves state that changes another's result.

Network

Cause: tests hit a real, slow, or rate-limited service.

Animations

Cause: CSS transitions race the assertion in e2e tests.

Race conditions

Cause: assertion fires before the UI/data reaches its final state.

Sleeps vs auto-waiting

Replace arbitrary waits with assertions that retry until the condition holds.

Retries (last resort) + quarantine

Retries hide flakes; quarantine isolates them. Neither is a fix.

TDD2

Red-green-refactor

Write a failing test, make it pass minimally, then clean up.

When TDD helps / doesn't

Shines on clear specs and bug fixes; awkward for exploratory UI work.

Anti-patterns7

Testing implementation details

Asserting on internals (private methods, exact calls) instead of behavior.

Snapshot abuse

Giant auto-generated snapshots that everyone blindly updates.

Slow unit tests

'Unit' tests that hit a DB, network, or filesystem — really slow integration tests.

Shared mutable fixtures

A fixture mutated by one test, corrupting others.

Asserting on logs

Verifying behavior by checking log output instead of real effects.

No-assert test

A test that runs code but never asserts — green even when broken.

Conditional logic in tests

if/else, loops, or try/catch deciding what a test asserts.