You are viewing documentation for v14 alpha. This version is under active development and APIs may change.

Custom render function

Summary

RNTL exposes the render function as the primary entry point for tests. If you make complex, repeating setups for your tests, consider creating a custom render function. The idea is to encapsulate common setup steps and test wiring inside a render function suitable for your tests.

Example

test-utils.ts
// ...

interface RenderWithProvidersProps {
  user?: User | null;
  theme?: Theme;
}

export async function renderWithProviders<T>(
  ui: React.ReactElement<T>,
  options?: RenderWithProvidersProps
) {
  return await render(
    <UserProvider.Provider value={options?.user ?? null}>
      <ThemeProvider.Provider value={options?.theme ?? 'light'}>{ui}</ThemeProvider.Provider>
    </UserProvider.Provider>
  );
}
custom-render/index.test.tsx
import { screen } from '@testing-library/react-native';
import { renderWithProviders } from '../test-utils';
// ...

test('renders WelcomeScreen with user', async () => {
  await renderWithProviders(<WelcomeScreen />, { user: { name: 'Jar-Jar' } });
  expect(screen.getByText(/hello Jar-Jar/i)).toBeOnTheScreen();
});

test('renders WelcomeScreen without user', async () => {
  await renderWithProviders(<WelcomeScreen />, { user: null });
  expect(screen.getByText(/hello stranger/i)).toBeOnTheScreen();
});

Example full source code.

More info

Additional params

A custom render function might accept additional parameters to allow for setting up different start conditions for a test, e.g., the initial state for global state management.

SomeScreen.test.tsx
test('renders SomeScreen for logged in user', async () => {
  await renderScreen(<SomeScreen />, { state: loggedInState });
  // ...
});

Multiple functions

Depending on the situation, you may declare more than one custom render function. For example, you have one function for testing application flows and a second for testing individual screens.

test-utils.tsx
function renderNavigator(ui, options);
function renderScreen(ui, options);

Async setup

Since render is async, your custom render function should be marked as async and use await render(). This pattern also makes it easy to add additional async setup if needed:

SomeScreen.test.tsx
async function renderWithData<T>(ui: React.ReactElement<T>) {
  const data = await fetchTestData();
  return await render(<DataProvider value={data}>{ui}</DataProvider>);
}

test('renders SomeScreen', async () => {
  await renderWithData(<SomeScreen />);
  // ...
});

Need React or React Native expertise you can count on?