← Back to React Testing Library Mastery
Advanced20 min read

Advanced Topics

Custom render, providers, setup patterns, and accessibility testing.

Setup and Teardown

Centralize test setup in test-utils.tsx: custom render with Redux, Router, Theme, i18n providers. Export render, screen re-export for single import path.

Reset MSW handlers, clear mock localStorage, reset Zustand store in afterEach.

export function renderWithProviders(ui: React.ReactElement, options = {}) {
  return render(ui, {
    wrapper: AllProviders,
    ...options,
  });
}

Custom Render

Wrapper composes all context providers test targets need. Optional override initial state for Redux or QueryClient per test.

Preconfigure userEvent in helper: export async function setup(ui) { const user = userEvent.setup(); return { user, ...renderWithProviders(ui) }; }

const { user } = await setup(<Dashboard />);
await user.click(screen.getByRole("link", { name: /settings/i }));

Testing with Providers

React Query: new QueryClient with retry false per test. Router: MemoryRouter with initialEntries. i18n: I18nextProvider with test namespace.

Avoid provider nesting duplication—one AllTheProviders wrapper maintained by platform team.

  • Mock router navigation with user.click and assert pathname via screen
  • Auth context: render with logged-in vs logged-out provider states
  • Theme: test dark mode toggle asserts class or data-theme attribute

Accessibility Testing

getByRole enforces accessible markup—missing labels cause test failure early. Add jest-axe or @axe-core/react for automated WCAG rule scan in select tests.

Manual keyboard tab order tests complement axe—automated tools miss all issues.

import { axe, toHaveNoViolations } from "jest-axe";
expect.extend(toHaveNoViolations);

const { container } = render(<Form />);
expect(await axe(container)).toHaveNoViolations();

Portals and Modals

Modal content may render in document.body portal—screen queries still find by role. Use within dialog role scope for assertions inside modal.

Wait for dialog appearance with findByRole after open click; assert aria-modal and focus trap optionally.

await user.click(screen.getByRole("button", { name: /open/i }));
const dialog = await screen.findByRole("dialog");
within(dialog).getByRole("button", { name: /confirm/i });

Get In Touch


Ready to discuss your next project? Drop me a message.