← Files Testing React Native AppsARCHIVED FILE
skills/react-native-testing/references/api-reference-v14.md
18.6 KB · Oct 2, 2026 · 00:30 UTC
# RNTL v14 API Reference
Complete API reference for `@testing-library/react-native` v14.x (React 19+).
**Test renderer:** `test-renderer` (not `react-test-renderer`)
**Element type:** `HostElement` (not `ReactTestInstance`)
## Table of Contents
- Core Pattern
- Key Rule: Always await
- render
- screen
- Queries
- User Event
- Fire Event
- Jest Matchers
- Async Utilities
- Other Helpers
- renderHook
- act
- Configuration
- Accessibility
- Removed APIs
- Migration Codemods
---
## Core Pattern
```tsx
import { render, screen, userEvent } from '@testing-library/react-native';
jest.useFakeTimers(); // recommended when using userEvent
test('description', async () => {
const user = userEvent.setup();
await render(<Component />); // async in v14 — always await
const button = screen.getByRole('button', { name: 'Submit' });
await user.press(button);
expect(screen.getByText('Done')).toBeOnTheScreen();
});
```
---
## Key Rule: Always `await`
In v14, the following APIs are **async** and must always be awaited:
- `await render(<Component />)`
- `await fireEvent.press(element)` (and all fireEvent variants)
- `await screen.rerender(<Component />)`
- `await screen.unmount()`
- `await renderHook(() => useHook())`
- `await act(() => { ... })` (even with sync callbacks)
---
## render
```ts
async function render(
component: React.Element<any>,
options?: RenderOptions,
): Promise<RenderResult>;
```
`render` returns a `Promise<RenderResult>` — always `await` it.
There is no `renderAsync` in v14. The standard `render` is already async.
### Options
| Option | Type | Description |
| ---------------- | -------------------------- | ----------------------------------------------------- |
| `wrapper` | `React.ComponentType<any>` | Wraps tested component (useful for context providers) |
| `createNodeMock` | `(element) => unknown` | Custom mock refs |
Note: `concurrentRoot` and `unstable_validateStringsRenderedWithinText` are removed in v14 (concurrent rendering is always on, string validation is always on).
### Example
```tsx
import { render, screen } from '@testing-library/react-native';
await render(<MyApp />);
expect(screen.getByRole('button', { name: 'start' })).toBeOnTheScreen();
// With wrapper
await render(<MyComponent />, {
wrapper: ({ children }) => <ThemeProvider>{children}</ThemeProvider>,
});
```
---
## screen
```ts
let screen: {
...queries;
rerender(element: React.Element<unknown>): Promise<void>; // async
unmount(): Promise<void>; // async
debug(options?: { message?: string; mapProps?: MapPropsFunction }): void;
toJSON(): RendererJSON | null;
container: HostElement; // safe root host element
root: HostElement; // root host element
};
```
The `screen` object provides queries and utilities for the currently rendered UI. Assigned after `render()`, cleared after each test via auto-cleanup.
### Methods
- **`rerender(element)`** — Re-render with new root element. **Async** — must `await`. Triggers lifecycle events.
- **`unmount()`** — Unmount the tree. **Async** — must `await`. Usually not needed (auto-cleanup).
- **`debug({ message?, mapProps? })`** — Pretty-print the rendered tree. Use `mapProps` to filter/transform props in output.
- **`toJSON()`** — Get JSON representation (for snapshot testing).
- **`container`** — Root host element (safe accessor, replaces `UNSAFE_root`).
- **`root`** — Root host element.
Note: `UNSAFE_root` is removed in v14. Use `container` or `root` instead.
---
## Queries
Each query = **variant** + **predicate** (e.g., `getByRole` = `getBy` + `ByRole`).
### Query Variants
| Variant | Assertion | Return Type | Async |
| ------------- | ------------------ | ------------------------------------ | ----- |
| `getBy*` | Exactly one match | `HostElement` (throws if 0 or >1) | No |
| `getAllBy*` | At least one match | `HostElement[]` (throws if 0) | No |
| `queryBy*` | Zero or one match | `HostElement \| null` (throws if >1) | No |
| `queryAllBy*` | No assertion | `HostElement[]` (empty if 0) | No |
| `findBy*` | Exactly one match | `Promise<HostElement>` | Yes |
| `findAllBy*` | At least one match | `Promise<HostElement[]>` | Yes |
`findBy*` / `findAllBy*` accept optional `waitForOptions: { timeout?, interval?, onTimeout? }`.
### Query Predicates
#### `*ByRole` (preferred)
```ts
getByRole(role: TextMatch, options?: {
name?: TextMatch;
disabled?: boolean;
selected?: boolean;
checked?: boolean | 'mixed';
busy?: boolean;
expanded?: boolean;
value?: { min?: number; max?: number; now?: number; text?: TextMatch };
includeHiddenElements?: boolean;
}): HostElement;
```
Matches elements by `role` or `accessibilityRole`. Element must be an accessibility element:
- `Text`, `TextInput`, `Switch` are by default
- `View` needs `accessible={true}` (or use `Pressable`/`TouchableOpacity`)
Common roles: `button`, `text`, `heading` (alias: `header`), `searchbox`, `switch`, `checkbox`, `radio`, `img`, `link`, `alert`, `menu`, `menuitem`, `tab`, `tablist`, `progressbar`, `slider`, `spinbutton`, `timer`, `toolbar`.
```tsx
screen.getByRole('button', { name: 'Submit' });
screen.getByRole('button', { name: 'Submit', disabled: true });
screen.getByRole('checkbox', { checked: true });
screen.getByRole('slider', { value: { now: 50, min: 0, max: 100 } });
```
#### `*ByLabelText`
```ts
getByLabelText(text: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches by `aria-label`/`accessibilityLabel` or text content of element referenced by `aria-labelledby`/`accessibilityLabelledBy`.
#### `*ByPlaceholderText`
```ts
getByPlaceholderText(text: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches `TextInput` by `placeholder` prop.
#### `*ByText`
```ts
getByText(text: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches by text content. Joins `<Text>` siblings to find matches (like RN runtime).
#### `*ByDisplayValue`
```ts
getByDisplayValue(value: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches `TextInput` by current display value.
#### `*ByHintText`
```ts
getByHintText(hint: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches by `accessibilityHint` prop. Also available as `getByA11yHint` / `getByAccessibilityHint`.
#### `*ByTestId` (last resort)
```ts
getByTestId(testId: TextMatch, options?: { exact?: boolean; normalizer?: Function; includeHiddenElements?: boolean }): HostElement;
```
Matches by `testID` prop. Use only when other queries don't work.
### TextMatch
```ts
type TextMatch = string | RegExp;
```
- **String**: exact full match by default. Use `{ exact: false }` for case-insensitive substring match.
- **RegExp**: substring match by default. Use anchors (`^...$`) for full match.
```tsx
screen.getByText('Hello World'); // exact full match
screen.getByText('llo Worl', { exact: false }); // substring, case-insensitive
screen.getByText(/World/); // regex substring
screen.getByText(/^hello world$/i); // regex full match, case-insensitive
```
### Common Query Options
- **`includeHiddenElements`** (alias: `hidden`): Include elements hidden from accessibility. Default: `false`.
- **`exact`**: Default `true`. When `false`, matches substrings case-insensitively. No effect on RegExp.
- **`normalizer`**: Custom text normalization function. Default trims whitespace and collapses multiple spaces. Use `getDefaultNormalizer({ trim?, collapseWhitespace? })` to customize.
---
## User Event
Prefer `userEvent` over `fireEvent`. User Event simulates realistic interaction sequences on **host elements only**, with proper event data.
### Setup
```ts
const user = userEvent.setup(options?: { delay?: number; advanceTimers?: (delay: number) => Promise<void> | void });
```
### `press(element)`
```ts
await user.press(element): Promise<void>;
```
Full press lifecycle: `pressIn` → `press` → `pressOut`. Minimum 130ms. Use fake timers to speed up.
### `longPress(element, options?)`
```ts
await user.longPress(element, { duration?: number }): Promise<void>;
```
Long press (default 500ms). Emits `pressIn`, `longPress`, `pressOut`.
### `type(element, text, options?)`
```ts
await user.type(textInput, text: string, options?: {
skipPress?: boolean; // skip pressIn/pressOut
skipBlur?: boolean; // skip endEditing/blur
submitEditing?: boolean; // trigger submitEditing
}): Promise<void>;
```
Character-by-character typing on `TextInput`. Appends to existing text (use `clear()` first to replace).
Event sequence per character: `keyPress` → `change` → `changeText` → `selectionChange` (+ `contentSizeChange` for multiline).
### `clear(element)`
```ts
await user.clear(textInput): Promise<void>;
```
Clears `TextInput` content. Events: `focus` → `selectionChange` → `keyPress` → `change` → `changeText` → `selectionChange` → `endEditing` → `blur`.
### `paste(element, text)`
```ts
await user.paste(textInput, text: string): Promise<void>;
```
Pastes text into `TextInput`. Events: `focus` → `selectionChange` → `change` → `changeText` → `selectionChange` → `endEditing` → `blur`.
### `scrollTo(element, options)`
```ts
await user.scrollTo(scrollView, options: {
y: number; momentumY?: number; // vertical scroll
// OR
x: number; momentumX?: number; // horizontal scroll
contentSize?: { width: number; height: number };
layoutMeasurement?: { width: number; height: number };
}): Promise<void>;
```
Scrolls a host `ScrollView` (including `FlatList`). Match scroll direction to `horizontal` prop. Pass `contentSize` and `layoutMeasurement` for `FlatList` updates. Remembers last scroll position between calls.
---
## Fire Event
Use when `userEvent` doesn't support the event or when triggering events on composite elements.
**Async** in v14 — always `await`:
```ts
async function fireEvent(
element: HostElement,
eventName: string,
...data: unknown[]
): Promise<void>;
```
Traverses tree bottom-up looking for `onXxx` handler. Does **not** auto-pass event data.
### Convenience Methods
```ts
await fireEvent.press(element, ...data): Promise<void>;
await fireEvent.changeText(element, ...data): Promise<void>;
await fireEvent.scroll(element, ...data): Promise<void>;
```
There is no `fireEventAsync` in v14. The standard `fireEvent` is already async.
---
## Jest Matchers
Available automatically with any `@testing-library/react-native` import. No setup needed.
### Element Existence
| Matcher | Description |
| ------------------- | --------------------------------------- |
| `toBeOnTheScreen()` | Element is attached to the element tree |
### Element Content
| Matcher | Signature | Description |
| --------------------- | ------------------------------------------------------------- | --------------------------- |
| `toHaveTextContent()` | `(text: string \| RegExp, options?: { exact?, normalizer? })` | Text content match |
| `toContainElement()` | `(element: HostElement \| null)` | Contains child element |
| `toBeEmptyElement()` | — | No children or text content |
### Element State
| Matcher | Description |
| ------------------------------------------------------- | ----------------------------------------------------- |
| `toHaveDisplayValue(value: string \| RegExp, options?)` | TextInput display value |
| `toHaveAccessibilityValue({ min?, max?, now?, text? })` | Accessibility value (partial match) |
| `toBeEnabled()` / `toBeDisabled()` | Disabled state via `aria-disabled` (checks ancestors) |
| `toBeSelected()` | Selected state via `aria-selected` |
| `toBeChecked()` / `toBePartiallyChecked()` | Checked state via `aria-checked` |
| `toBeExpanded()` / `toBeCollapsed()` | Expanded state via `aria-expanded` |
| `toBeBusy()` | Busy state via `aria-busy` |
### Element Style
| Matcher | Description |
| -------------------------------------- | --------------------------------------------------------------- |
| `toBeVisible()` | Not hidden (`display: none`, `opacity: 0`, or hidden from a11y) |
| `toHaveStyle(style: StyleProp<Style>)` | Specific style match |
### Other
| Matcher | Signature | Description |
| ------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------------- |
| `toHaveAccessibleName()` | `(name?: string \| RegExp, options?: { exact?, normalizer? })` | Accessible name from `aria-label`/`aria-labelledby` or text content |
| `toHaveProp()` | `(name: string, value?: unknown)` | Prop existence/value check (last resort) |
---
## Async Utilities
### `waitFor`
```ts
function waitFor<T>(
expectation: () => T,
options?: { timeout?: number; interval?: number },
): Promise<T>;
```
Runs `expectation` every `interval` (default 50ms) until `timeout` (default 1000ms). Callback must **throw** on failure. Auto-detects and works with Jest fake timers.
Rules:
- No side effects inside callback (no `fireEvent`/`userEvent`)
- One assertion per `waitFor`
- Never pass empty callback
- Prefer `findBy*` over `waitFor` + `getBy*`
### `waitForElementToBeRemoved`
```ts
function waitForElementToBeRemoved<T>(
expectation: () => T,
options?: { timeout?: number; interval?: number },
): Promise<T>;
```
Waits until the queried element is removed. Element must be initially present.
---
## Other Helpers
### `within`
```ts
function within(element: HostElement): Queries;
```
Scoped queries on a subtree. Useful for querying within a single `FlatList` item or a specific screen.
```tsx
const item = within(screen.getByTestId('list-item-1'));
expect(item.getByText('Title')).toBeOnTheScreen();
```
### `cleanup`
```ts
function cleanup(): void;
```
Unmounts rendered trees and clears `screen`. Automatic after each test (if test runner supports `afterEach`). Don't call manually unless using `@testing-library/react-native/pure`.
---
## renderHook
**Async** in v14:
```ts
async function renderHook<Result, Props>(
hookFn: (props?: Props) => Result,
options?: { initialProps?: Props; wrapper?: React.ComponentType },
): Promise<{
result: { current: Result };
rerender: (props: Props) => Promise<void>;
unmount: () => Promise<void>;
}>;
```
There is no `renderHookAsync` in v14. The standard `renderHook` is already async.
Renders a test component that calls the provided hook. Use `act()` when calling functions returned by the hook that trigger state updates.
```tsx
const { result } = await renderHook(() => useCount());
expect(result.current.count).toBe(0);
await act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
// With wrapper
await renderHook(() => useHook(), {
wrapper: ({ children }) => <Provider>{children}</Provider>,
});
```
---
## act
In v14, `act` always returns a `Promise<T>` and must be awaited, even with sync callbacks:
```ts
async function act<T>(callback: () => T): Promise<T>;
```
```tsx
await act(() => {
result.current.increment();
});
```
Usually not needed — `render`, `fireEvent`, `userEvent`, and `waitFor` handle it internally.
---
## Configuration
```ts
function configure(
options: Partial<{
asyncUtilTimeout: number; // default timeout for waitFor/findBy* (default: 1000ms)
defaultIncludeHiddenElements: boolean; // default for includeHiddenElements option (default: false)
defaultDebugOptions: Partial<DebugOptions>;
}>,
): void;
function resetToDefaults(): void;
```
Note: `concurrentRoot` option is removed (always on). `unstable_validateStringsRenderedWithinText` is removed (always on).
### Environment Variables
| Variable | Description |
| ---------------------------------------- | ----------------------------------------- |
| `RNTL_SKIP_AUTO_CLEANUP=true` | Disable automatic cleanup after each test |
| `RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS=true` | Disable auto-detection of fake timers |
---
## Accessibility
### `isHiddenFromAccessibility`
```ts
function isHiddenFromAccessibility(element: HostElement | null): boolean;
```
Also available as `isInaccessible()` alias.
Element is hidden when it or any ancestor has:
- `display: none` style
- `aria-hidden={true}`
- `accessibilityElementsHidden={true}` (iOS)
- `importantForAccessibility="no-hide-descendants"` (Android)
- Sibling with `aria-modal={true}` or `accessibilityViewIsModal={true}` (iOS)
---
## Removed APIs
The following are removed in v14 and must not be used:
- **`renderAsync`** — Use `render` (already async)
- **`fireEventAsync`** — Use `fireEvent` (already async)
- **`renderHookAsync`** — Use `renderHook` (already async)
- **`rerenderAsync` / `unmountAsync`** — Use `rerender` / `unmount` (already async)
- **`update()`** — Use `rerender()`
- **`getQueriesForElement()`** — Use `within()`
- **`UNSAFE_root`** — Use `container` or `root`
- **`UNSAFE_getByType`**, **`UNSAFE_getAllByType`**, **`UNSAFE_queryByType`**, **`UNSAFE_queryAllByType`** — Removed
- **`UNSAFE_getByProps`**, **`UNSAFE_getAllByProps`**, **`UNSAFE_queryByProps`**, **`UNSAFE_queryAllByProps`** — Removed
- **`concurrentRoot` option** — Always on
- **`unstable_validateStringsRenderedWithinText` option** — Always on
---
## Migration Codemods
Use RNTL codemods to automate migration from v13:
- **`rntl-v14-update-deps`** — Updates `react-test-renderer` to `test-renderer` in `package.json`
- **`rntl-v14-async-functions`** — Adds `await` to `render`, `fireEvent`, `rerender`, `unmount`, `renderHook`, and `act` calls
SHA-256: 29c3da4628abcc432e42a691b99d02fc1cb2ac019a4deb88a6e6424f6a12e65a