Review & Cheat Sheet: Testing Strategies

[!NOTE] This module explores the core principles of Review & Cheat Sheet: Testing Strategies, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.

1. Key Takeaways

  • Test Behavior, Not Implementation: Avoid testing internal state (props, state). Test what the user sees (text, buttons).
  • The Testing Trophy: Focus heavily on Integration Tests using React Testing Library (RTL). They give the best return on investment (ROI).
  • Query Priority: Always prefer getByRole for accessibility. Use getByTestId only as a last resort.
  • Async Testing: Use findBy... or waitFor for elements that appear after an API call.
  • E2E for Critical Paths: Use Playwright for “happy path” user flows (Login → Checkout). Use auto-waiting to avoid flakiness.
  • Mock Network, Not Client: Use MSW to intercept requests at the network layer. This tests your actual data fetching logic.
  • Global Setup: Use Playwright’s global setup to handle authentication once and reuse state across tests.

2. Interactive Flashcards

Question

Click to flip

Answer

1 / 5

3. Cheat Sheet: RTL Queries

Type Single Element Multiple Elements Async (Wait)? Returns if Missing Use Case
Get getBy... getAllBy... No Error Standard assertion
Query queryBy... queryAllBy... No null Assert absence (not.toBeInTheDocument)
Find findBy... findAllBy... Yes Error (timeout) Async elements (API data)

Common Matchers (jest-dom)

expect(element).toBeInTheDocument();
expect(element).toBeVisible();
expect(element).toHaveTextContent(/hello/i);
expect(element).toHaveAttribute('src', 'logo.png');
expect(element).toBeDisabled();
expect(input).toHaveValue('user input');

4. Anatomy of an RTL Test (The AAA Pattern)

Testing UI components typically follows the Arrange, Act, Assert (AAA) pattern:

test('submits form and displays success message', async () => {
  // 1. Arrange: Render the component and set up initial state/mocks
  const user = userEvent.setup();
  render(<ContactForm />);

  // 2. Act: Simulate user interactions
  await user.type(screen.getByRole('textbox', { name: /email/i }), 'test@example.com');
  await user.click(screen.getByRole('button', { name: /submit/i }));

  // 3. Assert: Verify the expected outcome on the screen
  expect(await screen.findByText(/success/i)).toBeInTheDocument();
});

5. Mnemonics: The RTL Query Family

To remember when to use which query type, think of them as different types of workers:

  • getBy... (The Bouncer): Strict. Expects the element to be there right now. If it’s missing, or if there’s more than one, the Bouncer throws an error and stops the show immediately.
  • queryBy... (The Receptionist): Polite. You ask, “Is element X here?” If yes, they hand it over. If no, they calmly return null. Perfect for verifying that an error message isn’t on the screen.
  • findBy... (The Detective): Patient. You say, “I know element X will show up eventually.” The Detective waits (returns a Promise) until the element appears or until the timeout is reached. Use for anything appearing after an API call or timer.

6. Industry War Story: The Flaky Test Epidemic

Scenario: A large e-commerce team had an integration test suite that failed randomly 15% of the time in CI, blocking releases. The Culprit: The tests used fireEvent.change() combined with hardcoded setTimeout(..., 500) to wait for debounced search results. Depending on CI server load, 500ms was sometimes too fast, causing random failures. The Fix:

  1. Replaced fireEvent with userEvent.type(), which accurately simulates the delays between real keystrokes.
  2. Replaced the hardcoded setTimeout with await screen.findByRole('listitem'). Result: RTL’s findBy automatically retries the assertion until it passes or times out (default 1000ms), making the test 100% resilient to CPU load variations without artificially slowing down fast runs.

7. Quick Revision

  1. Unit Tests: Test logic in isolation.
  2. Integration Tests: Test components working together (RTL). Focus here.
  3. E2E Tests: Test full user flows (Playwright).
  4. Static Analysis: ESLint/TypeScript catch typos.

React Glossary