testing-rtl-msw
RTL query conventions and the MSW network-mocking contract used by every unit/component test in this template. test-author loads this skill automatically.
Files1
View on GitHubSKILL.md.claude/skills/testing-rtl-msw/SKILL.md
GitHub- Query priority (matches RTL's own recommendation):
getByRolewith an accessiblenamefirst (screen.getByRole("button", { name: /subscribe/i })), thengetByLabelText,getByText; reach fordata-testid(getByTestId) only when no accessible query exists — seetests/unit/subscribe-dialog.test.tsxand the one deliberate exception,data-testid="subscriber-count"on plain display text with no other role. - Every test that touches a component using
fetchneeds the MSW server running (tests/unit/setup.tsalready wiresbeforeAll(() => server.listen(...)),afterEach(() => server.resetHandlers())) — you do not set this up per-test file, it's global. onUnhandledRequest: "error"is deliberate and must never be weakened to"warn"or"bypass"in this template: a test that reaches real network is a failing test, not a passing one with a warning. Add a handler insrc/mocks/handlers.tsinstead.- Reset any mutable mock state between tests (
resetSubscriberCount()intests/unit/setup.ts'safterEach) — a test must never depend on execution order. - Wrap components under test with the app's real providers via the shared
renderWithProvidershelper (tests/unit/test-utils.tsx), not a bespoke wrapper per test file — keepsQueryClientdefaults (retry: false) consistent everywhere. - Prefer
userEvent(@testing-library/user-event) overfireEventfor anything a real user would do (click, type) — it dispatches the fuller sequence of events real interaction produces. - A test's
it(...)description should read as a behavior, and a// covers: EARS-Ncomment ties it back tospecs/<feature>/spec.md(SPEC.md §8's testability contract) —reviewerchecks this traceability.