Edit this page
Learn how to create integration tests for your app when using Expo Router.
Expo Router relies on your file system, which can present challenges when setting up mocks for integration tests. Expo Router's submodule, expo-router/testing-library
, is a set of testing utilities built on top of the popular @testing-library/react-native
and allows you to quickly create in-memory Expo Router apps that are pre-configured for testing.
Before you proceed, ensure you have set up jest-expo
according to the Unit testing with Jest and @testing-library/react-native
in your project.
Note: When using Expo Router, do not put your test files inside the app directory. All files inside your app folder must be either routes or layout files. Instead, use the __tests__ directory or a separate directory. This approach is explained in Unit testing with Jest.
@testing-library/jest-native
provides custom Jest matchers that can be used to extend the functionality of @testing-library/react-native
. If installed, Expo Router will automatically perform the @testing-library/jest-native
setup.
renderRouter
renderRouter
extends the functionality of render
to simplify testing with Expo Router. It returns the same query object as render
, and is compatible with screen
, allowing you to use the standard query API to locate components.
renderRouter
accepts the same options as render
and introduces an additional option initialUrl
, which sets an initial route for simulating deep-linking.
Inline file system
renderRouter(mock: Record<string, ReactComponent>, options: RenderOptions)
renderRouter
can provide inline-mocking of a file system by passing an object to this function as the first parameter. The keys of the object are the mock filesystem paths. Do not use leading relative (./
) or absolute (/
) notation when defining these paths and exclude file extension.
import { renderRouter, screen } from 'expo-router/testing-library';
it('my-test', async () => {
const MockComponent = jest.fn(() => <View />);
renderRouter(
{
index: MockComponent,
'directory/a': MockComponent,
'(group)/b': MockComponent,
},
{
initialUrl: '/directory/a',
}
);
expect(screen).toHavePathname('/directory/a');
});
Inline file system with `null` components
renderRouter(mock: string[], options: RenderOptions)
Providing an array of strings to renderRouter
will create an inline mock filesystem with null
components ({ default: () => null }
). This is useful for testing scenarios where you do not need to test the output of a route.
import { renderRouter, screen } from 'expo-router/testing-library';
it('my-test', async () => {
renderRouter(['index', 'directory/a', '(group)/b'], {
initialUrl: '/directory/a',
});
expect(screen).toHavePathname('/directory/a');
});
Path to fixture
renderRouter(fixturePath: string, options: RenderOptions)
renderRouter
can accept a directory path to mock an existing fixture. Ensure that the provided path is relative to the current test file.
it('my-test', async () => {
const MockComponent = jest.fn(() => <View />);
renderRouter('./my-test-fixture');
});
Path to the fixture with overrides
renderRouter({ appDir: string, overrides: Record<string, ReactComponent>}, options: RenderOptions)
For more intricate testing scenarios, renderRouter
can leverage both directory path and inline-mocking methods simultaneously. The appDir
parameter takes a string representing a pathname to a directory. The overrides parameter is an inline mock that can be used to override specific paths within the appDir
. This combination allows for fine-tuned control over the mock environment.
it('my-test', async () => {
const MockAuthLayout = jest.fn(() => <View />);
renderRouter({
appDir: './my-test-fixture',
overrides: {
'directory/(auth)/_layout': MockAuthLayout,
},
});
});
The following matches have been added to expect
and can be used to assert values on screen
.
toHavePathname()
Assert the current pathname against a given string. The matcher uses the value of the usePathname
hook on the current screen
.
expect(screen).toHavePathname('/my-router');
toHavePathnameWithParams()
Assert the current pathname, including URL parameters, against a given string. This is useful to assert the appearance of URL in a web browser.
expect(screen).toHavePathnameWithParams('/my-router?hello=world');
toHaveSegments()
Assert the current segments against an array of strings. The matcher uses the value of the useSegments
hook on the current screen
.
expect(screen).toHaveSegments(['[id]']);
useLocalSearchParams()
Assert the current local URL parameters against an object. The matcher uses the value of the useLocalSearchParams
hook on the current screen
.
expect(screen).useLocalSearchParams({ first: 'abc' });
useGlobalSearchParams()
Assert the current screen's pathname that matches a value. Compares using the value of useGlobalSearchParams
hook.
Assert the current global URL parameters against an object. The matcher uses the value of the useGlobalSearchParams
hook on the current screen
.
expect(screen).useGlobalSearchParams({ first: 'abc' });
toHaveRouterState()
An advanced matcher that asserts the current router state against an object.
expect(screen).toHaveRouterState({
routes: [{ name: 'index', path: '/' }],
});