Test Writer — React
Write clear, maintainable tests for a React/TypeScript app with Vitest, React Testing Library, and MSW.
Use this skill when
- Testing a component, custom hook, or service/adapter layer
- You need MSW handlers for the network boundary
- You're unsure whether to mock or use the real implementation
Do not use this skill when
- The task is project structure → use
hexagonal-react-patterns - The task is async patterns design → use
async-react-patterns - The task is Python or NestJS testing → use
test-writer-python/test-writer-nestjs
🎯 Golden Rule (non-negotiable)
- Real implementations for ALL internal components (hooks, context providers, stores, services, domain utilities)
- Mocks ONLY for outbound adapters toward external systems (REST APIs, third-party SDKs, analytics, storage)
- Real infrastructure via testcontainers for integration / E2E tests that need a real backend (Postgres, Redis, LocalStack) — see
references/testcontainers.md
A stub/fake that diverges silently from the real implementation produces tests that pass but don't detect real regressions. Mocking only the network boundary keeps cost low and confidence high.
🎯 Workflow
- Ask for context — which component, hook, or service needs testing?
- Read the source code — understand props, state, side effects, external dependencies.
- Classify dependencies — internal → real impl; external → mock via
vi.mock+ fixtures intests/fixtures/external.tsor MSW handlers. - Load templates —
references/setup.md(vitest config, custom render);references/component-test.md;references/hook-test.md;references/msw.mdfor API boundary;references/testcontainers.mdfor real-backend E2E. - Write tests — AAA pattern, query by role, explicit names, one logical behavior per test.
- Run —
pnpm vitest(seereferences/commands.md).
🛡️ Edge cases (mandatory coverage)
Every test suite MUST cover edge cases, not just the happy path. For each component / hook / service under test, include tests for:
- Null / undefined props — pass
nullorundefinedto optional props, assert graceful rendering (no crash, shows fallback/empty state) - Empty / boundary values — empty array
[], empty string"",0, single-item list, very long string (truncation/overflow), very large list (virtualization/pagination) - Loading / error / empty states — assert the component renders loading skeleton, error message, and empty state correctly (not just the success state)
- Async edge cases — slow API response, network error, aborted request, race condition (fast response arrives after slow one), Suspense fallback
- User interaction edge cases — double-click submit (debounce/throttle), disabled button click, keyboard navigation, form submission with invalid data
- MSW error handlers — add MSW handlers returning 4xx / 5xx / network error / empty response, not just 200 happy path
- Accessibility edge cases — missing aria-label, no children, RTL languages, very long content
If the component/hook has validation logic or business rules, add at least one test per rule that violates it and asserts the correct error/fallback UI.
What you never do
- Write a fake store, fake context, or fake hook to replace a real internal implementation
- Mock a React component under test or any component in its subtree
- Mock Zustand, React Query, or any other internal state manager
- Assert on internal implementation details (spy on a private function, check component state directly)
- Use
waitForpolling as a workaround for missingawaiton user events - Forget
userEvent.setup()— never use the legacyuserEventwithout it
Related skills
hexagonal-react-patterns— project structure, layer rules, CVA variantsasync-react-patterns— async patterns (test the patterns you implement)
References
references/setup.md— vitest config, test structure, custom render with providersreferences/component-test.md— component test with real store + MSW for APIreferences/hook-test.md— hook test withrenderHook,act,waitForreferences/msw.md— MSW server setup and per-test handlersreferences/testcontainers.md— real infrastructure for integration / E2E tests (Redis, Postgres, LocalStack)references/commands.md— vitest commands (run, watch, coverage, single test)