Skip to content

Commit 0954367

Browse files
committed
async events
1 parent c6fc0a0 commit 0954367

7 files changed

Lines changed: 50 additions & 36 deletions

File tree

website/docs/14.x/cookbook/advanced/network-requests.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ afterAll(() => server.close());
246246

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

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

330330
await waitForElementToBeRemoved(() => screen.getByText(/users data not quite there yet/i));
331331
expect(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
["async-tests", "custom-render"]
1+
["async-events", "custom-render"]

website/docs/14.x/cookbook/basics/async-tests.md renamed to website/docs/14.x/cookbook/basics/async-events.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
# Async tests
1+
# Async Events
22

33
## Summary
44

5-
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:
5+
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:
66

7-
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.
8-
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.
7+
1. **Waiting for elements to appear**: Use `findBy*` queries when elements appear after some delay (e.g., after data fetching).
8+
2. **Waiting for conditions**: Use `waitFor()` to wait for arbitrary conditions to be met.
9+
3. **Waiting for elements to disappear**: Use `waitForElementToBeRemoved()` when elements should be removed after some action.
910

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

1213
### Example
1314

14-
Consider a basic asynchronous test for a user signing in with correct credentials:
15+
Consider a test for a user signing in with correct credentials:
1516

1617
```javascript
1718
test('User can sign in with correct credentials', async () => {

website/docs/14.x/cookbook/basics/custom-render.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ interface RenderWithProvidersProps {
1616

1717
export async function renderWithProviders<T>(
1818
ui: React.ReactElement<T>,
19-
options?: RenderWithProvidersProps
19+
options?: RenderWithProvidersProps,
2020
) {
2121
return await render(
2222
<UserProvider.Provider value={options?.user ?? null}>
2323
<ThemeProvider.Provider value={options?.theme ?? 'light'}>{ui}</ThemeProvider.Provider>
24-
</UserProvider.Provider>
24+
</UserProvider.Provider>,
2525
);
2626
}
2727
```
@@ -51,8 +51,8 @@ Example [full source code](https://github.com/callstack/react-native-testing-lib
5151
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.
5252

5353
```tsx title=SomeScreen.test.tsx
54-
test('renders SomeScreen for logged in user', () => {
55-
renderScreen(<SomeScreen />, { state: loggedInState });
54+
test('renders SomeScreen for logged in user', async () => {
55+
await renderScreen(<SomeScreen />, { state: loggedInState });
5656
// ...
5757
});
5858
```
@@ -66,13 +66,18 @@ function renderNavigator(ui, options);
6666
function renderScreen(ui, options);
6767
```
6868

69-
#### Async function
69+
#### Async setup
7070

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

7373
```tsx title=SomeScreen.test.tsx
74+
async function renderWithData<T>(ui: React.ReactElement<T>) {
75+
const data = await fetchTestData();
76+
return await render(<DataProvider value={data}>{ui}</DataProvider>);
77+
}
78+
7479
test('renders SomeScreen', async () => {
75-
await renderWithAsync(<SomeScreen />);
80+
await renderWithData(<SomeScreen />);
7681
// ...
7782
});
7883
```

website/docs/14.x/cookbook/state-management/jotai.md

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,18 @@ We can test our `TaskList` component using React Native Testing Library's (RNTL)
6565
function. Although it is sufficient to test the empty state of the `TaskList` component, it is not
6666
enough to test the component with initial tasks present in the list.
6767

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

7676
jest.useFakeTimers();
7777

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

91-
```tsx title=status-management/jotai/test-utils.tsx
91+
```tsx title=state-management/jotai/__tests__/test-utils.tsx
9292
import * as React from 'react';
9393
import { render } from '@testing-library/react-native';
9494
import { useHydrateAtoms } from 'jotai/utils';
@@ -108,14 +108,14 @@ export interface RenderWithAtomsOptions {
108108
* @param options - The render options including the initial atom values.
109109
* @returns The render result from `@testing-library/react-native`.
110110
*/
111-
export const renderWithAtoms = <T,>(
111+
export async function renderWithAtoms<T>(
112112
component: React.ReactElement,
113-
options: RenderWithAtomsOptions
114-
) => {
115-
return render(
116-
<HydrateAtomsWrapper initialValues={options.initialValues}>{component}</HydrateAtomsWrapper>
113+
options: RenderWithAtomsOptions,
114+
) {
115+
return await render(
116+
<HydrateAtomsWrapper initialValues={options.initialValues}>{component}</HydrateAtomsWrapper>,
117117
);
118-
};
118+
}
119119

120120
export type HydrateAtomsWrapperProps = React.PropsWithChildren<{
121121
initialValues: AtomInitialValueTuple<unknown>[];
@@ -144,12 +144,11 @@ We can now use the `renderWithAtoms` function to render the `TaskList` component
144144
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.
145145
:::
146146

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

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

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

207206
//...
208207

website/docs/14.x/docs/start/intro.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ You want to write maintainable tests for your React Native components. As a part
66

77
## This solution
88

9-
The React Native Testing Library (RNTL) is a lightweight solution for testing React Native components. It provides light utility functions on top of [Test Renderer](https://github.com/mdjastrzebski/test-renderer), in a way that encourages better testing practices. Its primary guiding principle is:
9+
The React Native Testing Library (RNTL) is a comprehensive solution for testing React Native components. It provides React Native runtime simulation on top of [Test Renderer](https://github.com/mdjastrzebski/test-renderer), in a way that encourages better testing practices. Its primary guiding principle is:
1010

1111
> The more your tests resemble how your software is used, the more confidence they can give you.
1212
@@ -23,7 +23,7 @@ test('form submits two answers', async () => {
2323
const onSubmit = jest.fn();
2424

2525
const user = userEvent.setup();
26-
render(<QuestionsBoard questions={questions} onSubmit={onSubmit} />);
26+
await render(<QuestionsBoard questions={questions} onSubmit={onSubmit} />);
2727

2828
const answerInputs = screen.getAllByLabelText('answer input');
2929
await user.type(answerInputs[0], 'a1');

website/docs/14.x/docs/start/quick-start.mdx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@ Open a Terminal in your project's folder and run:
1313
}}
1414
/>
1515

16-
This library uses [Test Renderer](https://github.com/mdjastrzebski/test-renderer) as its underlying renderer. Test Renderer is automatically installed as a dependency and provides better compatibility with React 19 and improved type safety compared to the deprecated [React Test Renderer](https://reactjs.org/docs/test-renderer.html).
16+
This library has a peer dependency on [Test Renderer](https://github.com/mdjastrzebski/test-renderer). Make sure to install it:
17+
18+
<PackageManagerTabs
19+
command={{
20+
yarn: 'yarn add -D test-renderer',
21+
npm: 'npm install -D test-renderer',
22+
}}
23+
/>
24+
25+
Test Renderer provides better compatibility with React 19 and improved type safety compared to the deprecated [React Test Renderer](https://reactjs.org/docs/test-renderer.html).
1726

1827
### Jest matchers
1928

0 commit comments

Comments
 (0)