contentintech
Intermediate

Testing Cheatsheet

Quick reference for testing — Vitest/Jest APIs, matchers, mocking recipes, supertest and Playwright snippets, and TDD checklists.

Unit TestsVitestTDDPlaywright
NotesCheatsheet

Test Structure

Vitest / Jest Skeleton (AAA)

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';

describe('feature', () => {
  beforeEach(() => { /* fresh setup */ });
  afterEach(() => { vi.restoreAllMocks(); });

  it('does the thing', () => {
    const input = makeInput();      // Arrange
    const out   = doThing(input);   // Act
    expect(out).toBe(expected);     // Assert
  });
});

Lifecycle Hooks

HookRuns
beforeAllOnce before the whole block
beforeEachBefore every test
afterEachAfter every test (cleanup)
afterAllOnce after the whole block

Modifiers

it.only(...)    // run just this test
it.skip(...)    // skip
it.todo('name') // placeholder
it.each([[a, b]])('$a -> $b', (a, b) => { ... });

Matchers

MatcherChecks
toBe(x)=== / reference identity
toEqual(x)Deep structural equality
toStrictEqual(x)Deep + types + undefined keys
toBeTruthy / toBeNullTruthiness / null
toContain(x)Array member or substring
toHaveLength(n)Array/string length
toMatch(/re/)String against regex
toMatchObject(x)Subset of object props
toThrow(err)Function throws
toBeCloseTo(n)Floating-point equality
.not / .resolves / .rejectsNegate / await a promise
expect(x).not.toBe(y);
await expect(promise).resolves.toEqual(v);
await expect(promise).rejects.toThrow(/msg/);
expect(fn).toThrow(TypeError);

Mocking

Functions & Spies

const fn = vi.fn();
fn.mockReturnValue(42);
fn.mockResolvedValue({ ok: true });   // async
fn.mockImplementation((x) => x * 2);

vi.spyOn(obj, 'method').mockReturnValue(1);

expect(fn).toHaveBeenCalled();
expect(fn).toHaveBeenCalledTimes(2);
expect(fn).toHaveBeenCalledWith('arg');
expect(fn).toHaveReturnedWith(42);

Modules & Timers

vi.mock('./db', () => ({ query: vi.fn() }));
vi.clearAllMocks();     // reset call history
vi.restoreAllMocks();   // undo spies

vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));
vi.advanceTimersByTime(1000);
vi.useRealTimers();

Test Doubles

TypeRole
StubCanned return values
SpyRecords real calls
MockProgrammed + verified
FakeLightweight working impl

Integration & E2E

Supertest (API)

import request from 'supertest';
import { app } from '../app';

const res = await request(app)
  .post('/api/login')
  .set('Authorization', 'Bearer <token>')
  .send({ email, password });

expect(res.status).toBe(200);
expect(res.body).toHaveProperty('token');
expect(res.headers['content-type']).toMatch(/json/);

Playwright (E2E)

import { test, expect } from '@playwright/test';

test('login', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('a@b.com');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Dashboard' }))
    .toBeVisible();
  await expect(page).toHaveURL(/\/dashboard/);
});

Preferred Locators

LocatorUse
getByRoleButtons, headings, links (best)
getByLabelForm fields
getByTextNon-interactive content
getByTestIdLast resort

TDD, Snapshots & CLI

TDD Cycle

StepDo
RedWrite a failing test
GreenSimplest code to pass
RefactorClean up, stay green

Snapshots

expect(node).toMatchSnapshot();
expect(slug).toMatchInlineSnapshot(`"hello-world"`);
// update intentionally:  vitest -u

CLI

vitest              # watch mode
vitest run          # single run (CI)
vitest run --coverage
vitest -t "login"   # filter by name
vitest related src/x.ts   # tests touching a file
playwright test --ui      # Playwright debug UI

Coverage Metrics

MetricMeaning
Statements% of statements run
BranchesEach if/else side hit (best signal)
Functions% of functions called
Lines% of lines executed

Section navigation