accelint-react-testing
React Testing Best Practices
Expert guidance for writing maintainable, user-centric React component tests with Testing Library. Focused on query selection, accessibility-first testing, and avoiding implementation details.
NEVER Do When Writing React Tests
- NEVER query by test IDs before trying accessible queries - Test IDs bypass accessibility verification: a button with
data-testid="submit"but no accessible name works in tests but fails for screen reader users. When tests pass with test IDs, you ship inaccessible UIs. Query hierarchy:getByRole>getByLabelText>getByText>getByTestId. Each step down this list means less confidence your UI is usable. - NEVER use
fireEventfor user interactions whenuserEventis available -fireEventdispatches single DOM events, missing the event sequence real users trigger:fireEvent.click()fires one click event, but real users trigger focus → mousedown → mouseup → click. Components that work with fireEvent break in production when users interact normally.userEvent.click()simulates the full interaction sequence, catching bugs fireEvent misses. - NEVER test implementation details instead of user behavior - Tests that verify "state variable X equals Y" or "function Z was called" create false failures: you refactor from useState to useReducer, all tests fail, yet the UI works identically. Testing implementation details punishes refactoring and provides zero confidence the user experience works. Test what users see and do (rendered output, interaction results), not how your component achieves it internally.
- NEVER query from
containeror use destructured queries after initial render -const { getByText } = render(<Component />)creates stale queries that miss updates: after state changes, destructured queries search the initial DOM snapshot, missing newly rendered elements. This causes "element not found" errors for elements that are actually present. Always usescreen.getByText()which automatically queries the current DOM state. Using screen consistently also makes tests more maintainable - adding a new query doesn't require updating the destructuring. - NEVER add aria-label or role attributes solely for tests - If you're adding
aria-label="submit-button"orrole="button"just so tests can find elements, you're working backwards. Tests should verify the component is already accessible, not make it accessible for tests. Adding test-only ARIA pollutes production code and masks real accessibility problems. Fix the component's semantic HTML and existing ARIA first. - NEVER snapshot entire component trees without specific assertions - Massive snapshots with 500+ lines break on any change (updated classname, new prop, reordered elements), forcing reviewers to approve diffs they can't meaningfully evaluate. When test failures require "just update the snapshot" without understanding why, the test has zero value. Snapshot specific critical structures (error messages, data tables) with targeted assertions for everything else.
- NEVER use
waitForfor actions that return promises -waitFor(() => expect(element).toBeInTheDocument())polls repeatedly until timeout when a promise-basedfindByquery solves it in one shot:await screen.findByText('loaded')waits for the element to appear without polling. Reserve waitFor for assertions that can't use findBy (checking element disappears, waiting for attribute changes). - NEVER perform side effects inside waitFor callback -
waitFor(() => { fireEvent.click(button); expect(text).toBeInTheDocument(); })runs the click multiple times as waitFor retries, causing unpredictable behavior. waitFor is for waiting on assertions, not triggering actions. Perform all actions outside waitFor, then use waitFor only for the assertion:fireEvent.click(button); await waitFor(() => expect(text).toBeInTheDocument());or better yet,await userEvent.click(button); expect(await screen.findByText(text)).toBeInTheDocument();. - NEVER create custom renders without documenting provider requirements - A custom
renderWithReduxfunction with undocumented required store shape breaks for every developer: they callrender(<Component />)instead ofrenderWithRedux(), tests fail with cryptic "Cannot read property of undefined", wasting 15 minutes debugging. Centralize provider setup in test utils with TypeScript types that enforce correct usage, or document required wrappers prominently. - NEVER mix queries from different Testing Library imports - Importing both
@testing-library/reactrender and@testing-library/domqueries creates confusion:screenfrom react package doesn't work withgetByRolefrom dom package, causing "screen.getByRole is not a function" errors. Import all queries from@testing-library/reactfor React components - it re-exports everything from dom with React-specific enhancements.
Before Writing Tests, Ask
More from gohypergiant/agent-skills
accelint-nextjs-best-practices
Next.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.
221accelint-ts-testing
Comprehensive vitest testing guidance for TypeScript projects. Use when (1) Writing new tests with AAA pattern, parameterized tests, or async/await, (2) Reviewing test code for anti-patterns like loose assertions (toBeTruthy), over-mocking, or nested describe blocks, (3) Optimizing slow test suites, (4) Implementing property-based testing with fast-check - especially for encode/decode pairs, roundtrip properties, validators, normalizers, and idempotence checks. Covers test organization, assertions, test doubles hierarchy (fakes/stubs/mocks), async testing, performance patterns, and property-based testing patterns. Trigger keywords on vitest, *.test.ts, describe, it, expect, vi.mock, fast-check, fc.property, roundtrip, idempotence.
213accelint-react-best-practices
React performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
183accelint-ts-performance
Systematic JavaScript/TypeScript performance audit and optimization using V8 profiling and runtime patterns. Use when (1) Users say 'optimize performance', 'audit performance', 'this is slow', 'reduce allocations', 'improve speed', 'check performance', (2) Analyzing code for performance anti-patterns (O(n²) complexity, excessive allocations, I/O blocking, template literal waste), (3) Optimizing functions regardless of current usage context - utilities, formatters, parsers are often called in hot paths even when they appear simple, (4) Fixing V8 deoptimization (monomorphic/polymorphic issues, inline caching). Audits ALL code for anti-patterns and reports findings with expected gains. Covers loops, caching, batching, memory locality, algorithmic complexity fixes with ❌/✅ patterns.
173accelint-ts-best-practices
Comprehensive TypeScript/JavaScript coding standards focusing on type safety, defensive programming, and code correctness. Use when (1) Writing or reviewing TS/JS code, (2) Fixing type errors or avoiding any/enum/null, (3) Implementing control flow, state management, or error handling, (4) Applying zero-value pattern or immutability, (5) Code review for TypeScript anti-patterns. Covers naming conventions, function design, return values, bounded iteration, input validation. For performance optimization, use accelint-ts-performance skill. For documentation, use accelint-ts-documentation skill.
166accelint-readme-writer
Use when creating or editing a README.md file in any project or package. Recursively parses codebase from README location, suggests changes based on missing or changed functionality, and generates thorough, human-sounding documentation with copy-pasteable code blocks and practical examples.
160