For dApps & ServicesLedger WalletContributing to Ledger WalletHow-to GuidesHow to Use the Custom Renderer

How to Use the Custom Test Renderer

This guide shows you how to use the custom render utilities provided by Ledger Wallet to test components and hooks with all necessary providers pre-configured.

Always prefer the custom render utilities over raw @testing-library render functions.


How to render a component (Mobile)

Import from @tests/test-renderer:

import { render, screen } from "@tests/test-renderer";
import { State } from "~/reducers/types";
 
const { user, store } = render(<MyComponent />, {
  overrideInitialState: (state: State) => ({
    ...state,
    accounts: {
      ...state.accounts,
      active: [mockAccount],
    },
  }),
});
 
// Use screen queries
expect(screen.getByText("Hello")).toBeTruthy();
 
// Simulate user interactions
await user.press(screen.getByText("Submit"));

How to render a component (Desktop)

Import from tests/testSetup:

import { render, screen } from "tests/testSetup";
 
const { user, store, i18n } = render(<MyComponent />, {
  initialState: {
    accounts: { active: [mockAccount] },
  },
  initialRoute: "/accounts", // Optional: set initial route
});
 
// Use screen queries
expect(screen.getByText("Hello")).toBeInTheDocument();
 
// Simulate user interactions
await user.click(screen.getByRole("button", { name: "Submit" }));

How to render a hook

Mobile

import { renderHook } from "@tests/test-renderer";
 
const { result, store } = renderHook(() => useMyCustomHook(), {
  overrideInitialState: (state) => ({
    ...state,
    settings: { ...state.settings, theme: "dark" },
  }),
});
 
expect(result.current.value).toBe(expectedValue);

Desktop

import { renderHook } from "tests/testSetup";
 
const { result, store } = renderHook(() => useMyCustomHook(), {
  initialState: {
    settings: { theme: "dark" },
  },
});
 
expect(result.current.value).toBe(expectedValue);

How to customize initial state

Use overrideInitialState (Mobile) or initialState (Desktop) to set up Redux state for your tests:

  • Mobile: Pass a function that receives the full default state and returns the modified state. You must spread the existing state to avoid replacing reducer defaults.
  • Desktop: Pass a partial state object that is merged into the default state.
// Mobile - function-based override
render(<MyComponent />, {
  overrideInitialState: (state: State) => ({
    ...state,
    settings: { ...state.settings, theme: "dark" },
  }),
});
 
// Desktop - object-based override
render(<MyComponent />, {
  initialState: {
    settings: { theme: "dark" },
  },
});

Before vs After: why use the custom renderer

Before (manual provider setup)

🚫

This approach requires manually wrapping components with many providers:

import { render } from "@testing-library/react-native";
import { Provider } from "react-redux";
import { ThemeProvider } from "styled-components";
import { NavigationContainer } from "@react-navigation/native";
import { FirebaseFeatureFlagsProvider } from "~/components/FirebaseFeatureFlags";
// ... many more imports
 
const mockStore = createMockStore({ accounts: [mockAccount] });
 
render(
  <Provider store={mockStore}>
    <FirebaseFeatureFlagsProvider getFeature={getFeature}>
      <NavigationContainer>
        <ThemeProvider theme={theme}>
          <I18nextProvider i18n={i18n}>
            <MyComponent />
          </I18nextProvider>
        </ThemeProvider>
      </NavigationContainer>
    </FirebaseFeatureFlagsProvider>
  </Provider>
);

After (using custom renderer)

The custom renderer handles all provider setup automatically:

import { render, screen } from "@tests/test-renderer";
 
const { user, store } = render(<MyComponent />, {
  overrideInitialState: (state) => ({
    ...state,
    accounts: { ...state.accounts, active: [mockAccount] },
  }),
});

Mocks you no longer need

When using the custom render utilities, remove these commonly unnecessary mocks:

// ❌ No need to mock react-i18next - I18nextProvider is included
jest.mock("react-i18next", () => ({
  useTranslation: () => ({
    t: (key) => key,
  }),
}));
 
// ❌ No need to mock react-redux - Provider with real store is included
jest.mock("react-redux", () => ({
  useSelector: jest.fn(),
  useStore: jest.fn(() => ({})),
}));
 
// ❌ No need to mock theme-related hooks
jest.mock("~/hooks/useTheme", () => ({
  useTheme: () => ({ colors: { /* ... */ } }),
}));

See also

Ledger
Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Stax, Ledger Flex, Ledger Nano, Ledger Nano S, Ledger OS, Ledger Wallet, [LEDGER] (logo), [L] (logo) are trademarks owned by Ledger SAS.