Loading...
Loading...
Write tests using React Native Testing Library (RNTL) v13 and v14 (`@testing-library/react-native`). Use when writing, reviewing, or fixing React Native component tests. Covers: render, screen, queries (getBy/getAllBy/queryBy/findBy), Jest matchers, userEvent, fireEvent, waitFor, and async patterns. Supports v13 (React 18, sync render) and v14 (React 19+, async render). Triggers on: test files for React Native components, RNTL imports, mentions of "testing library", "write tests", "component tests", or "RNTL".
npx skill4agent add callstack/react-native-testing-library react-native-testing@testing-library/react-native@testing-library/react-nativepackage.jsontest-rendererreact-test-renderergetByRolegetByLabelTextgetByPlaceholderTextgetByTextgetByDisplayValuegetByTestId| Variant | Use case | Returns | Async |
|---|---|---|---|
| Element must exist | element instance (throws) | No |
| Multiple must exist | element instance[] (throws) | No |
| Check non-existence ONLY | element instance | null | No |
| Count elements | element instance[] | No |
| Wait for element | | Yes |
| Wait for multiple | | Yes |
userEventfireEventconst user = userEvent.setup();
await user.press(element); // full press sequence
await user.longPress(element, { duration: 800 }); // long press
await user.type(textInput, 'Hello'); // char-by-char typing
await user.clear(textInput); // clear TextInput
await user.paste(textInput, 'pasted text'); // paste into TextInput
await user.scrollTo(scrollView, { y: 100 }); // scrollfireEventuserEventfireEvent.press(element);
fireEvent.changeText(textInput, 'new text');
fireEvent(element, 'blur');@testing-library/react-native| Matcher | Use for |
|---|---|
| Element exists in tree |
| Element visible (not hidden/display:none) |
| Disabled state via |
| Checked state |
| Selected state |
| Expanded state |
| Busy state |
| Text content match |
| TextInput display value |
| Accessible name |
| Accessibility value |
| Style match |
| Prop check (last resort) |
| Contains child element |
| No children |
screenrender()getByRole{ name: '...' }queryBy*.not.toBeOnTheScreen()findBy*waitForgetBy*waitForfireEventuserEventwaitForwaitForact()renderfireEventuserEventcleanup()rolearia-labelaria-disabledaccessibility**ByRolebuttontextheadingheadersearchboxswitchcheckboxradioimglinkalertmenumenuitemtabtablistprogressbarsliderspinbuttontimertoolbargetByRole{ name, disabled, selected, checked, busy, expanded, value: { min, max, now, text } }*ByRoleTextTextInputSwitchViewaccessible={true}PressableTouchableOpacity// Correct: action first, then wait for result
fireEvent.press(button);
await waitFor(() => {
expect(screen.getByText('Result')).toBeOnTheScreen();
});
// Better: use findBy* instead
fireEvent.press(button);
expect(await screen.findByText('Result')).toBeOnTheScreen();waitFor(cb, { timeout: 1000, interval: 50 })userEventjest.useFakeTimers();
test('with fake timers', async () => {
const user = userEvent.setup();
render(<Component />);
await user.press(screen.getByRole('button'));
// ...
});wrapperfunction renderWithProviders(ui: React.ReactElement) {
return render(ui, {
wrapper: ({ children }) => (
<ThemeProvider>
<AuthProvider>{children}</AuthProvider>
</ThemeProvider>
),
});
}