Testing Prompts

Prompts for unit tests, integration tests, E2E testing, mocking, and test infrastructure.

#38 Testing

Unit Test Suite with Mocking

Write a thorough unit-test suite in TypeScript with Vitest (or Jest) for a UserService that performs CRUD over a repository. Test BEHAVIOR, not implementation: create (valid input, duplicate email rejected, validation errors), read (by id, not-found, paginated list), update (partial update, optimistic-concurrency conflict), and delete (soft delete sets the flag, cascade/guard checks). Mock ONLY the repository/DB boundary (via vi.mock or dependency injection) so the service's own logic runs for real, and assert on both the return values and the calls made to the mock (arguments and call count). Use describe blocks, beforeEach/afterEach for isolated state, and an arrange-act-assert structure with descriptive test names that read as specifications. Include error-path tests (the repo throws → the service maps it to a domain error) and at least one snapshot of a response shape. Avoid the anti-patterns: no shared mutable state across tests, no asserting on private internals, and no over-mocking that ends up testing the mock instead of the code. Done when the suite is deterministic and order-independent, covers the happy and error paths for every method, exceeds 90% coverage on the service, and the test names alone document the behavior.

#39 Testing

Integration Test for API Endpoints

Write integration tests in TypeScript (Vitest/Jest + Supertest) that exercise a REST resource (e.g. /api/posts) through the REAL HTTP stack and a real test database — mock nothing below the route handler. Cover the full matrix: GET list with pagination and filtering, GET one (found and 404), POST (valid → 201 with the created body, validation error → 422, unauthenticated → 401), PUT (owner can update, non-owner → 403, missing → 404), DELETE (owner and admin-override, plus idempotency), and assert the consistent error envelope on every failure path. Use a real PostgreSQL test database — Testcontainers or a dedicated test DB — migrated once and reset between tests (transaction rollback or truncate) so tests are isolated and parallel-safe. Provide an auth helper that mints valid JWTs for seeded test users of each role. Assert the status, the body shape, AND any side effect in the database. Done when the suite runs against a fresh database, each test is independent of execution order and of other tests' data, every status path including authorization is covered, and the error response format is verified against real responses rather than assumed.

#40 Testing

E2E Test with Playwright

Write end-to-end tests with Playwright + TypeScript for a web app's critical journeys. Cover: registration (fill, submit, assert the redirect to the dashboard and a persisted session), login (valid credentials, wrong password shows an error, remember-me), creating an item (fill the form, upload an image, submit, assert it appears in the list), and search/filter (type a query, apply filters, assert the results update and the URL reflects the state). Run the create and search specs across desktop, tablet, and mobile viewport projects. Make the tests ROBUST, not flaky: select by user-facing roles and labels (getByRole/getByLabel) rather than brittle CSS selectors, rely on Playwright's auto-waiting and web-first assertions instead of fixed sleeps, and isolate each test with its own data and a fresh storage state (use a global setup to authenticate once and reuse the session where appropriate). Seed and clean test data via the API rather than clicking through the UI, for speed. Capture a screenshot, video, and trace on failure. Done when the suite passes RELIABLY across all three viewports, contains no hard-coded waits, each test is independent, and a failure produces a trace that makes the cause obvious.

#41 Testing

API Contract Testing

Set up API contract tests in TypeScript that guarantee responses match an agreed schema, using Zod (or JSON Schema) as the single source of truth. For each endpoint, define the response schema precisely: required vs optional fields, types, nested object and array-item shapes, enum values, nullability, and formats (uuid, email, ISO date). Write tests that hit the running API and parse every response through its schema, failing on any extra, missing, or mistyped field — and assert that the success shape AND the error shapes (400/401/404/422/500) all conform to their contracts, since error formats are what drift the most. Ideally derive the same Zod schemas the SERVER uses for runtime validation so the contract can't silently diverge from the implementation, and generate OpenAPI/JSON-Schema docs from them. Add a test that fails loudly when the API starts returning an undocumented field. Done when every endpoint's success and error responses are validated against an explicit schema, the schemas are shared with (not duplicated from) the server, a contract-breaking change fails CI, and the API docs are generated from the schemas rather than hand-written.

#42 Testing

Visual Regression Testing Setup

Set up visual regression testing for a component library using Playwright's toHaveScreenshot (or Storybook + Chromatic). Create stories/specs that render each component in every meaningful state: a button in default/hover/focus/active/disabled/loading across size variants, a form showing validation errors, a modal (open, and with scrollable overflow content), a data table in empty/loading/populated/error states, and responsive navigation (desktop expanded vs mobile hamburger). Make the snapshots DETERMINISTIC — this is where visual tests live or die: freeze time and animations, disable transitions, wait for fonts and images to load, mask or stub dynamic content (dates, avatars, random data), and pin the viewport, device-scale, and OS rendering by generating baselines inside the SAME container/CI image so anti-aliasing doesn't cause false diffs. Set a small comparison threshold for AA noise and document how to review and intentionally update a baseline. Wire a CI job that runs on PRs and uploads the diff images as artifacts. Done when an unintended visual change fails the PR with a clear diff, the snapshots are stable across runs on CI (no flakiness from fonts, time, or animation), and updating a baseline is a deliberate, reviewable step rather than an accident.

#43 Testing

Test Data Factory

Build a typed test-data factory system in TypeScript (in the spirit of Fishery or FactoryBot) for User, Post, and Comment. Each factory produces a valid entity with faker-generated defaults, supports overriding any field per call, exposes traits for common variants (User.admin(), User.unverified()), and uses sequences for unique fields (email, username) so no two built records collide. Associations build their dependencies automatically — Post.create() creates and links a User unless one is passed in — without infinite recursion, and support batch creation (User.buildList(10)). Provide BOTH a pure build (in-memory, for unit tests) and an async create that persists to the test database (for integration tests), sharing one definition. Make it fully type-safe: the return type is inferred from the factory definition, overrides are type-checked against the entity, and traits compose. Keep generated data deterministic when a seed is set so a failure reproduces. Done when factories produce valid entities with unique sequenced fields, associations and traits compose without boilerplate, build and create share a single definition, and the inferred types catch an invalid override at COMPILE time.