Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f4aa736
chore: basic openskills setup
mdjastrzebski Jan 15, 2026
f333b62
code -review
mdjastrzebski Jan 15, 2026
31f1375
docs: move migration guide
mdjastrzebski Jan 15, 2026
2a50d49
docs: tweaks
mdjastrzebski Jan 15, 2026
d7c1b35
first draft
mdjastrzebski Jan 15, 2026
3369489
file locations
mdjastrzebski Jan 15, 2026
d543657
codemods note
mdjastrzebski Jan 15, 2026
fefdb9d
renderer wording
mdjastrzebski Jan 15, 2026
81a2224
host element links
mdjastrzebski Jan 15, 2026
f5a855a
package manager tabs
mdjastrzebski Jan 15, 2026
11f9aa3
.
mdjastrzebski Jan 15, 2026
1c087be
.
mdjastrzebski Jan 15, 2026
6e749ae
.
mdjastrzebski Jan 15, 2026
dd8be8c
async
mdjastrzebski Jan 15, 2026
6c369be
.
mdjastrzebski Jan 15, 2026
6430c2b
bun
mdjastrzebski Jan 15, 2026
be4f3cc
.
mdjastrzebski Jan 15, 2026
dcd826b
render docs
mdjastrzebski Jan 15, 2026
918516f
fire-event
mdjastrzebski Jan 15, 2026
4c60cf7
screen
mdjastrzebski Jan 15, 2026
5be3dc9
queries
mdjastrzebski Jan 15, 2026
66827c3
jest matchers
mdjastrzebski Jan 15, 2026
f4c22a6
user event
mdjastrzebski Jan 15, 2026
e039a3c
render hook
mdjastrzebski Jan 15, 2026
be6e11f
async utils
mdjastrzebski Jan 15, 2026
d0365dc
config
mdjastrzebski Jan 15, 2026
8e7029b
accessibility
mdjastrzebski Jan 15, 2026
9088b86
other
mdjastrzebski Jan 15, 2026
bcf7c0c
how should I query
mdjastrzebski Jan 15, 2026
efa32d5
react 19
mdjastrzebski Jan 15, 2026
236520b
react 19 refs
mdjastrzebski Jan 15, 2026
998c437
troubleshooting
mdjastrzebski Jan 15, 2026
203123c
testing env
mdjastrzebski Jan 15, 2026
5c625d9
undstanding act
mdjastrzebski Jan 15, 2026
b396af7
.
mdjastrzebski Jan 15, 2026
a42fa38
async act
mdjastrzebski Jan 15, 2026
c6fc0a0
readme
mdjastrzebski Jan 15, 2026
0954367
async events
mdjastrzebski Jan 15, 2026
3c6520e
.
mdjastrzebski Jan 15, 2026
7a38567
.
mdjastrzebski Jan 15, 2026
c3a428f
fix lint
mdjastrzebski Jan 15, 2026
9344d0c
.
mdjastrzebski Jan 15, 2026
88b1f69
.
mdjastrzebski Jan 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
538 changes: 538 additions & 0 deletions .claude/skills/code-review/SKILL.md

Large diffs are not rendered by default.

394 changes: 394 additions & 0 deletions .claude/skills/doc-coauthoring/SKILL.md

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,44 @@ The project uses `yarn` for dependency management and script execution.
- `src/index.ts`: Main entry point, re-exports `pure` and adds side effects (auto-cleanup).
- `examples/`: Example React Native applications using the library.
- `website/`: Documentation website.

<skills_system priority="1">

## Available Skills

<!-- SKILLS_TABLE_START -->
<usage>
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.

How to use skills:

- Invoke: Bash("openskills read <skill-name>")
- The skill content will load with detailed instructions on how to complete the task
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)

Usage notes:

- Only use skills listed in <available_skills> below
- Do not invoke a skill that is already loaded in your context
- Each skill invocation is stateless
</usage>

<available_skills>

<skill>
<name>code-review</name>
<description>Master effective code review practices to provide constructive feedback, catch bugs early, and foster knowledge sharing while maintaining team morale. Use when reviewing pull requests, establishing review standards, or mentoring developers.</description>
<location>project</location>
</skill>

<skill>
<name>doc-coauthoring</name>
<description>Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers. Trigger when user mentions writing docs, creating proposals, drafting specs, or similar documentation tasks.</description>
<location>project</location>
</skill>

</available_skills>

<!-- SKILLS_TABLE_END -->

</skills_system>
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ yarn add --dev @testing-library/react-native
npm install --save-dev @testing-library/react-native
```

This library has a `peerDependencies` listing for `test-renderer`. Make sure that your `test-renderer` version matches exactly the `react` version, avoid using `^` in version number.
This library has a `peerDependencies` listing for [Test Renderer](https://github.com/mdjastrzebski/test-renderer). Make sure to install it as a dev dependency:

```sh
# Yarn install:
yarn add --dev test-renderer

# NPM install
npm install --save-dev test-renderer
```

### Additional Jest matchers

Expand All @@ -57,7 +65,7 @@ test('form submits two answers', async () => {
const onSubmit = jest.fn();

const user = userEvent.setup();
render(<QuestionsBoard questions={questions} onSubmit={onSubmit} />);
await render(<QuestionsBoard questions={questions} onSubmit={onSubmit} />);

const answerInputs = screen.getAllByLabelText('answer input');

Expand Down Expand Up @@ -85,9 +93,9 @@ React Native Testing Library consists of following APIs:
- [`screen` object](https://callstack.github.io/react-native-testing-library/docs/api/screen) - access rendered UI:
- [Queries](https://callstack.github.io/react-native-testing-library/docs/api/queries) - find rendered components by various predicates: role, text, test ids, etc
- Lifecycle methods: [`rerender`](https://callstack.github.io/react-native-testing-library/docs/api/screen#rerender), [`unmount`](https://callstack.github.io/react-native-testing-library/docs/api/screen#unmount)
- Helpers: [`debug`](https://callstack.github.io/react-native-testing-library/docs/api/screen#debug), [`toJSON`](https://callstack.github.io/react-native-testing-library/docs/api/screen#tojson), [`root`](https://callstack.github.io/react-native-testing-library/docs/api/screen#root)
- Helpers: [`debug`](https://callstack.github.io/react-native-testing-library/docs/api/screen#debug), [`toJSON`](https://callstack.github.io/react-native-testing-library/docs/api/screen#tojson), [`root`](https://callstack.github.io/react-native-testing-library/docs/api/screen#root), [`container`](https://callstack.github.io/react-native-testing-library/docs/api/screen#container)
- [Jest matchers](https://callstack.github.io/react-native-testing-library/docs/api/jest-matchers) - validate assumptions about your UI
- [User Event](https://callstack.github.io/react-native-testing-library/docs/api/events/user-event) - simulate common user interactions like [`press`](https://callstack.github.io/react-native-testing-library/docs/api/events/user-event#press) or [`type`](https://callstack.github.io/react-native-testing-library/docs/user-event#type) in a realistic way
- [User Event](https://callstack.github.io/react-native-testing-library/docs/api/events/user-event) - simulate common user interactions like [`press`](https://callstack.github.io/react-native-testing-library/docs/api/events/user-event#press) or [`type`](https://callstack.github.io/react-native-testing-library/docs/api/events/user-event#type) in a realistic way
- [Fire Event](https://callstack.github.io/react-native-testing-library/docs/api/events/fire-event) - simulate any component event in a simplified way
- [`renderHook` function](https://callstack.github.io/react-native-testing-library/docs/api/misc/render-hook) - render hooks for testing purposes
- Miscellaneous APIs:
Expand All @@ -98,6 +106,7 @@ React Native Testing Library consists of following APIs:

## Migration Guides

- **[Migration to 14.0](https://callstack.github.io/react-native-testing-library/docs/migration/v14)** - Drops React 18, async APIs by default
- [Migration to 13.0](https://callstack.github.io/react-native-testing-library/docs/migration/v13)
- [Migration to built-in Jest Matchers](https://callstack.github.io/react-native-testing-library/docs/migration/jest-matchers)

Expand Down
2 changes: 1 addition & 1 deletion codemods/v14-update-deps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This codemod automatically updates your `package.json` to prepare for React Nati
- Removes `@types/react-test-renderer` and `react-test-renderer` (no longer needed)
- Moves `@testing-library/react-native` to `devDependencies` if it's in `dependencies`
- Updates `@testing-library/react-native` to `^14.0.0-alpha.5`
- Adds `test-renderer@0.12.0` to `devDependencies`
- Adds `test-renderer@0.14.0` to `devDependencies`

## Usage

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"jest": ">=29.0.0",
"react": ">=19.0.0",
"react-native": ">=0.78",
"test-renderer": "~0.13.2"
"test-renderer": "^0.14.0"
},
"peerDependenciesMeta": {
"jest": {
Expand Down Expand Up @@ -91,7 +91,7 @@
"react-native": "0.83.1",
"react-native-gesture-handler": "^2.29.1",
"release-it": "^19.0.6",
"test-renderer": "0.13.2",
"test-renderer": "0.14.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.47.0"
},
Expand Down
2 changes: 1 addition & 1 deletion src/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface RenderOptions {
export type RenderResult = Awaited<ReturnType<typeof render>>;

/**
* Renders test component deeply using React Test Renderer and exposes helpers
* Renders test component deeply using Test Renderer and exposes helpers
* to assert on the output.
*/
export async function render<T>(element: React.ReactElement<T>, options: RenderOptions = {}) {
Expand Down
4 changes: 2 additions & 2 deletions website/docs/14.x/cookbook/advanced/network-requests.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ afterAll(() => server.close());

describe('PhoneBook', () => {
it('fetches all contacts and favorites successfully and renders lists in sections correctly', async () => {
render(<PhoneBook />);
await render(<PhoneBook />);

await waitForElementToBeRemoved(() => screen.getByText(/users data not quite there yet/i));
expect(await screen.findByText('Name: Mrs Ida Kristensen')).toBeOnTheScreen();
Expand Down Expand Up @@ -325,7 +325,7 @@ describe('PhoneBook', () => {
...
it('fails to fetch all contacts and renders error message', async () => {
mockServerFailureForGetAllContacts();
render(<PhoneBook />);
await render(<PhoneBook />);

await waitForElementToBeRemoved(() => screen.getByText(/users data not quite there yet/i));
expect(
Expand Down
2 changes: 1 addition & 1 deletion website/docs/14.x/cookbook/basics/_meta.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
["async-tests", "custom-render"]
["async-events", "custom-render"]
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Async tests
# Async Events

## Summary

Typically, you would write synchronous tests, as they are simple and get the work done. However, there are cases when using asynchronous (async) tests might be necessary or beneficial. The two most common cases are:
In RNTL v14, all tests are async since `render()`, `fireEvent()`, and other core APIs return Promises. Beyond the basic async APIs, there are additional async utilities for handling events that complete over time:

1. **Testing Code with asynchronous operations**: When your code relies on asynchronous operations, such as network calls or database queries, async tests are essential. Even though you should mock these network calls, the mock should act similarly to the actual behavior and hence by async.
2. **UserEvent API:** Using the [User Event API](docs/api/events/user-event) in your tests creates more realistic event handling. These interactions introduce delays (even though these are typically event-loop ticks with 0 ms delays), requiring async tests to handle the timing correctly.
1. **Waiting for elements to appear**: Use `findBy*` queries when elements appear after some delay (e.g., after data fetching).
2. **Waiting for conditions**: Use `waitFor()` to wait for arbitrary conditions to be met.
3. **Waiting for elements to disappear**: Use `waitForElementToBeRemoved()` when elements should be removed after some action.

Using async tests when needed ensures your tests are reliable and simulate real-world conditions accurately.
These utilities help you write reliable tests that properly handle timing in your application.

### Example

Consider a basic asynchronous test for a user signing in with correct credentials:
Consider a test for a user signing in with correct credentials:

```javascript
test('User can sign in with correct credentials', async () => {
Expand Down
15 changes: 10 additions & 5 deletions website/docs/14.x/cookbook/basics/custom-render.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ Example [full source code](https://github.com/callstack/react-native-testing-lib
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.

```tsx title=SomeScreen.test.tsx
test('renders SomeScreen for logged in user', () => {
renderScreen(<SomeScreen />, { state: loggedInState });
test('renders SomeScreen for logged in user', async () => {
await renderScreen(<SomeScreen />, { state: loggedInState });
// ...
});
```
Expand All @@ -66,13 +66,18 @@ function renderNavigator(ui, options);
function renderScreen(ui, options);
```

#### Async function
#### Async setup

Make it async if you want to put some async setup in your custom render function.
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:

```tsx title=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 renderWithAsync(<SomeScreen />);
await renderWithData(<SomeScreen />);
// ...
});
```
29 changes: 14 additions & 15 deletions website/docs/14.x/cookbook/state-management/jotai.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ We can test our `TaskList` component using React Native Testing Library's (RNTL)
function. Although it is sufficient to test the empty state of the `TaskList` component, it is not
enough to test the component with initial tasks present in the list.

```tsx title=status-management/jotai/__tests__/TaskList.test.tsx
```tsx title=state-management/jotai/__tests__/TaskList.test.tsx
import * as React from 'react';
import { render, screen, userEvent } from '@testing-library/react-native';
import { renderWithAtoms } from './test-utils';
import { TaskList } from './TaskList';
import { newTaskTitleAtom, tasksAtom } from './state';
import { Task } from './types';
import { TaskList } from '../TaskList';
import { newTaskTitleAtom, tasksAtom } from '../state';
import { Task } from '../types';

jest.useFakeTimers();

test('renders an empty task list', () => {
render(<TaskList />);
test('renders an empty task list', async () => {
await render(<TaskList />);
expect(screen.getByText(/no tasks, start by adding one/i)).toBeOnTheScreen();
});
```
Expand All @@ -88,7 +88,7 @@ initial values. We can create a custom render function that uses Jotai's `useHyd
hydrate the atoms with initial values. This function will accept the initial atoms and their
corresponding values as an argument.

```tsx title=status-management/jotai/test-utils.tsx
```tsx title=state-management/jotai/__tests__/test-utils.tsx
import * as React from 'react';
import { render } from '@testing-library/react-native';
import { useHydrateAtoms } from 'jotai/utils';
Expand All @@ -108,14 +108,14 @@ export interface RenderWithAtomsOptions {
* @param options - The render options including the initial atom values.
* @returns The render result from `@testing-library/react-native`.
*/
export const renderWithAtoms = <T,>(
export async function renderWithAtoms<T>(
component: React.ReactElement,
options: RenderWithAtomsOptions
) => {
return render(
) {
return await render(
<HydrateAtomsWrapper initialValues={options.initialValues}>{component}</HydrateAtomsWrapper>
);
};
}

export type HydrateAtomsWrapperProps = React.PropsWithChildren<{
initialValues: AtomInitialValueTuple<unknown>[];
Expand Down Expand Up @@ -144,12 +144,11 @@ We can now use the `renderWithAtoms` function to render the `TaskList` component
In our test, we populated only one atom and its initial value, but you can add other Jotai atoms and their corresponding values to the initialValues array as needed.
:::

```tsx title=status-management/jotai/__tests__/TaskList.test.tsx
=======
```tsx title=state-management/jotai/__tests__/TaskList.test.tsx
const INITIAL_TASKS: Task[] = [{ id: '1', title: 'Buy bread' }];

test('renders a to do list with 1 items initially, and adds a new item', async () => {
renderWithAtoms(<TaskList />, {
await renderWithAtoms(<TaskList />, {
initialValues: [
[tasksAtom, INITIAL_TASKS],
[newTaskTitleAtom, ''],
Expand Down Expand Up @@ -202,7 +201,7 @@ No special setup is required to test these functions, as `store.set` is availabl
Jotai.

```tsx title=state-management/jotai/__tests__/TaskList.test.tsx
import { addTask, getAllTasks, store, tasksAtom } from './state';
import { addTask, getAllTasks, store, tasksAtom } from '../state';

//...

Expand Down
Loading