@testing-library/react-native 14.0.0-beta.1 → 14.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -6
- package/build/helpers/accessibility.js +24 -7
- package/build/helpers/accessibility.js.map +1 -1
- package/docs/README.md +31 -0
- package/docs/agents/architecture.md +21 -0
- package/docs/agents/build-and-validation.md +27 -0
- package/docs/agents/code-style.md +12 -0
- package/docs/agents/example-apps.md +56 -0
- package/docs/agents/git-workflow.md +13 -0
- package/docs/agents/testing.md +20 -0
- package/docs/api/accessibility.md +26 -0
- package/docs/api/async-utilities.md +137 -0
- package/docs/api/configuration.md +61 -0
- package/docs/api/fire-event.md +165 -0
- package/docs/api/jest-matchers.md +198 -0
- package/docs/api/other-helpers.md +94 -0
- package/docs/api/overview.md +18 -0
- package/docs/api/queries.md +500 -0
- package/docs/api/render-hook.md +176 -0
- package/docs/api/render.md +49 -0
- package/docs/api/screen.md +188 -0
- package/docs/api/user-event.md +295 -0
- package/docs/cookbook/async-events.md +147 -0
- package/docs/cookbook/custom-render.md +83 -0
- package/docs/cookbook/network-requests.md +375 -0
- package/docs/guides/common-mistakes.md +587 -0
- package/docs/guides/how-to-query.md +125 -0
- package/docs/guides/llm-guidelines.md +228 -0
- package/docs/guides/migration-v14.md +553 -0
- package/docs/guides/quick-start.md +77 -0
- package/docs/guides/testing-environment.md +123 -0
- package/docs/guides/troubleshooting.md +61 -0
- package/docs/guides/understanding-act.md +207 -0
- package/package.json +9 -8
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { PackageManagerTabs } from '@rspress/core/theme';
|
|
2
|
+
|
|
3
|
+
# Migration to 14.x
|
|
4
|
+
|
|
5
|
+
This guide describes the migration to React Native Testing Library version 14 from version 13.x.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
RNTL v14 drops support for React 18 and adopts React 19's async rendering model. Here's what changed:
|
|
10
|
+
|
|
11
|
+
- React 19.0.0+ and React Native 0.78+ are now required
|
|
12
|
+
- Node.js `^22.13.0 || >=24` is now required
|
|
13
|
+
- `render`, `renderHook`, `fireEvent`, and `act` are now async
|
|
14
|
+
- Switched from deprecated [React Test Renderer](https://reactjs.org/docs/test-renderer.html) to [Test Renderer](https://github.com/mdjastrzebski/test-renderer)
|
|
15
|
+
- Removed deprecated APIs: `update`, `getQueriesForElement`, `UNSAFE_root`, `concurrentRoot` option, `createNodeMock` option
|
|
16
|
+
- Reintroduced `container` API, which is now safe to use
|
|
17
|
+
|
|
18
|
+
> [!INFO] React 18 Users
|
|
19
|
+
> If you need to support React 18, please continue using RNTL v13.x.
|
|
20
|
+
|
|
21
|
+
## Quick Migration
|
|
22
|
+
|
|
23
|
+
We provide codemods to automate most of the migration:
|
|
24
|
+
|
|
25
|
+
**Step 1: Update dependencies**
|
|
26
|
+
|
|
27
|
+
<PackageManagerTabs
|
|
28
|
+
command={{
|
|
29
|
+
npm: 'npx codemod@latest rntl-v14-update-deps --target .\nnpm install',
|
|
30
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-update-deps --target .\nyarn install',
|
|
31
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-update-deps --target .\npnpm install',
|
|
32
|
+
bun: 'bunx codemod@latest rntl-v14-update-deps --target .\nbun install',
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
**Step 2: Update test code to async**
|
|
37
|
+
|
|
38
|
+
<PackageManagerTabs
|
|
39
|
+
command={{
|
|
40
|
+
npm: 'npx codemod@latest rntl-v14-async-functions --target ./src',
|
|
41
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-async-functions --target ./src',
|
|
42
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-async-functions --target ./src',
|
|
43
|
+
bun: 'bunx codemod@latest rntl-v14-async-functions --target ./src',
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
After running the codemods, review the changes and run your tests.
|
|
48
|
+
|
|
49
|
+
If your project uses coding agents, add the RNTL package-docs instruction snippet from the [Quick Start](./quick-start.md#agent-docs-in-the-package) so agents read the docs that match your installed package version.
|
|
50
|
+
|
|
51
|
+
## Breaking Changes
|
|
52
|
+
|
|
53
|
+
### Supported React, React Native, and Node.js versions
|
|
54
|
+
|
|
55
|
+
**This version requires React 19+, React Native 0.78+, and Node.js `^22.13.0 || >=24`.** If you need to support React 18, please use the latest v13.x version.
|
|
56
|
+
|
|
57
|
+
| RNTL Version | React Version | React Native Version | Node.js Version |
|
|
58
|
+
| ------------ | ------------- | -------------------- | ------------------ |
|
|
59
|
+
| v14.x | >= 19.0.0 | >= 0.78 | ^22.13.0 \|\| >=24 |
|
|
60
|
+
| v13.x | >= 18.0.0 | >= 0.71 | >= 18 |
|
|
61
|
+
|
|
62
|
+
### Test Renderer replaces React Test Renderer
|
|
63
|
+
|
|
64
|
+
In v14, React Native Testing Library uses [Test Renderer](https://github.com/mdjastrzebski/test-renderer) instead of the deprecated [React Test Renderer](https://reactjs.org/docs/test-renderer.html). Test Renderer works with React 19 and has better TypeScript support.
|
|
65
|
+
|
|
66
|
+
**What changed:**
|
|
67
|
+
|
|
68
|
+
- The underlying renderer is now Test Renderer instead of React Test Renderer
|
|
69
|
+
- This is mostly an internal change; your tests should work without modifications in most cases
|
|
70
|
+
- Type definitions now use [`TestInstance`](https://github.com/mdjastrzebski/test-renderer#test-instance) from Test Renderer instead of `ReactTestInstance`
|
|
71
|
+
- Test Renderer 1.x is required as a peer dependency. Use the recommended Test Renderer version for your React 19 minor version.
|
|
72
|
+
|
|
73
|
+
#### Recommended Test Renderer versions
|
|
74
|
+
|
|
75
|
+
Choose the Test Renderer version that matches your React 19 minor version:
|
|
76
|
+
|
|
77
|
+
| React version | Recommended Test Renderer version | Notable React features |
|
|
78
|
+
| ------------- | --------------------------------- | ------------------------------------------------- |
|
|
79
|
+
| `19.2` | `test-renderer@1.2` | `<Activity />`, `useEffectEvent` |
|
|
80
|
+
| `19.1` | `test-renderer@1.1` | Owner Stack support, updated `useId()` format |
|
|
81
|
+
| `19.0` | `test-renderer@1.0` | Actions, `useActionState`, `useOptimistic`, `use` |
|
|
82
|
+
|
|
83
|
+
Using an older Test Renderer line can prevent RNTL from supporting newer React 19 features in your tests. Using a newer Test Renderer line than your React version can produce peer dependency warnings, or an install error with `npm`.
|
|
84
|
+
|
|
85
|
+
See the [Test Renderer React 19 compatibility lines](https://github.com/mdjastrzebski/test-renderer#react-19-compatibility-lines) for the latest recommendations.
|
|
86
|
+
|
|
87
|
+
**Migration:**
|
|
88
|
+
|
|
89
|
+
#### 1. Update dependencies
|
|
90
|
+
|
|
91
|
+
Run codemod for updating dependencies:
|
|
92
|
+
|
|
93
|
+
<PackageManagerTabs
|
|
94
|
+
command={{
|
|
95
|
+
npm: 'npx codemod@latest rntl-v14-update-deps\nnpm install',
|
|
96
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-update-deps\nyarn install',
|
|
97
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-update-deps\npnpm install',
|
|
98
|
+
bun: 'bunx codemod@latest rntl-v14-update-deps\nbun install',
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
##### Manual changes
|
|
103
|
+
|
|
104
|
+
Remove React Test Renderer and its type definitions from your dev dependencies, and add the Test Renderer line that matches your React minor version:
|
|
105
|
+
|
|
106
|
+
<PackageManagerTabs
|
|
107
|
+
command={{
|
|
108
|
+
npm: 'npm uninstall react-test-renderer @types/react-test-renderer\nnpm install -D test-renderer@1.2',
|
|
109
|
+
yarn: 'yarn remove react-test-renderer @types/react-test-renderer\nyarn add -D test-renderer@1.2',
|
|
110
|
+
pnpm: 'pnpm remove react-test-renderer @types/react-test-renderer\npnpm add -D test-renderer@1.2',
|
|
111
|
+
bun: 'bun remove react-test-renderer @types/react-test-renderer\nbun add -D test-renderer@1.2',
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
The commands above use `test-renderer@1.2` for React 19.2. Use `test-renderer@1.1` for React 19.1, or `test-renderer@1.0` for React 19.0.
|
|
116
|
+
|
|
117
|
+
#### 2. Update type imports (if needed)
|
|
118
|
+
|
|
119
|
+
If you were directly importing types from React Test Renderer, you may need to update your imports:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
// Before (v13)
|
|
123
|
+
import type { ReactTestInstance } from 'react-test-renderer';
|
|
124
|
+
|
|
125
|
+
// After (v14)
|
|
126
|
+
import type { TestInstance } from 'test-renderer';
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Note:** Most users won't need to update type imports, as React Native Testing Library now exports the necessary types directly.
|
|
130
|
+
|
|
131
|
+
See the [Test Renderer documentation](https://github.com/mdjastrzebski/test-renderer) for more.
|
|
132
|
+
|
|
133
|
+
### Async APIs by Default
|
|
134
|
+
|
|
135
|
+
With React 18 support dropped, RNTL v14 uses React 19's async rendering model. The following functions are now async by default:
|
|
136
|
+
|
|
137
|
+
- `render()` → returns `Promise<RenderResult>`
|
|
138
|
+
- `rerender()` and `unmount()` → return `Promise<void>`
|
|
139
|
+
- `renderHook()` → returns `Promise<RenderHookResult>`
|
|
140
|
+
- `fireEvent()` and helpers (`press`, `changeText`, `scroll`) → return `Promise<void>`
|
|
141
|
+
- `act()` → always returns `Promise<T>`
|
|
142
|
+
|
|
143
|
+
> [!TIP] Already using async APIs?
|
|
144
|
+
> If you adopted the async APIs introduced in RNTL v13.3 (`renderAsync`, `fireEventAsync`, `renderHookAsync`), rename them to their non-async counterparts (`render`, `fireEvent`, `renderHook`). The async versions have been removed since the standard APIs are now async by default.
|
|
145
|
+
|
|
146
|
+
#### `render` is now async
|
|
147
|
+
|
|
148
|
+
In v14, `render` is async by default and returns a Promise. This allows proper support for `Suspense` boundaries and the `use()` hook.
|
|
149
|
+
|
|
150
|
+
**Before (v13):**
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { render, screen } from '@testing-library/react-native';
|
|
154
|
+
|
|
155
|
+
it('should render component', () => {
|
|
156
|
+
render(<MyComponent />);
|
|
157
|
+
expect(screen.getByText('Hello')).toBeOnTheScreen();
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**After (v14):**
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import { render, screen } from '@testing-library/react-native';
|
|
165
|
+
|
|
166
|
+
it('should render component', async () => {
|
|
167
|
+
await render(<MyComponent />);
|
|
168
|
+
expect(screen.getByText('Hello')).toBeOnTheScreen();
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
See the [`render` API documentation](../api/render.md).
|
|
173
|
+
|
|
174
|
+
#### `renderHook` is now async
|
|
175
|
+
|
|
176
|
+
In v14, `renderHook` is async by default and returns a Promise.
|
|
177
|
+
|
|
178
|
+
**Before (v13):**
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { renderHook } from '@testing-library/react-native';
|
|
182
|
+
|
|
183
|
+
it('should test hook', () => {
|
|
184
|
+
const { result, rerender } = renderHook(() => useMyHook());
|
|
185
|
+
|
|
186
|
+
rerender(newProps);
|
|
187
|
+
unmount();
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**After (v14):**
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { renderHook } from '@testing-library/react-native';
|
|
195
|
+
|
|
196
|
+
it('should test hook', async () => {
|
|
197
|
+
const { result, rerender } = await renderHook(() => useMyHook());
|
|
198
|
+
|
|
199
|
+
await rerender(newProps);
|
|
200
|
+
await unmount();
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
See the [`renderHook` API documentation](../api/render-hook.md).
|
|
205
|
+
|
|
206
|
+
#### `fireEvent` is now async
|
|
207
|
+
|
|
208
|
+
In v14, `fireEvent` and its helpers (`press`, `changeText`, `scroll`) are async by default and return a Promise.
|
|
209
|
+
|
|
210
|
+
**Before (v13):**
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { fireEvent, screen } from '@testing-library/react-native';
|
|
214
|
+
|
|
215
|
+
it('should press button', () => {
|
|
216
|
+
render(<MyComponent />);
|
|
217
|
+
fireEvent.press(screen.getByText('Press me'));
|
|
218
|
+
expect(onPress).toHaveBeenCalled();
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**After (v14):**
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { fireEvent, screen } from '@testing-library/react-native';
|
|
226
|
+
|
|
227
|
+
it('should press button', async () => {
|
|
228
|
+
await render(<MyComponent />);
|
|
229
|
+
await fireEvent.press(screen.getByText('Press me'));
|
|
230
|
+
expect(onPress).toHaveBeenCalled();
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
`fireEvent.press()` and `fireEvent.scroll()` now create default synthetic native event objects. If you pass event props, they are deep-merged into the default event object:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
await fireEvent.press(screen.getByText('Press me'), {
|
|
238
|
+
nativeEvent: { pageX: 20, pageY: 30 },
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(onPress).toHaveBeenCalledWith(
|
|
242
|
+
expect.objectContaining({
|
|
243
|
+
nativeEvent: expect.objectContaining({ pageX: 20, pageY: 30 }),
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
If your v13 assertions expected the handler to receive exactly the object you passed to `fireEvent.press()` or `fireEvent.scroll()`, update them to use partial matching.
|
|
249
|
+
|
|
250
|
+
#### `act` is now async
|
|
251
|
+
|
|
252
|
+
In v14, `act` is async by default and always returns a Promise. You should always `await` the result of `act()`.
|
|
253
|
+
|
|
254
|
+
**What changed:**
|
|
255
|
+
|
|
256
|
+
- `act` now always returns `Promise<T>` instead of `T | Thenable<T>`
|
|
257
|
+
- `act` should always be awaited
|
|
258
|
+
|
|
259
|
+
> [!NOTE]
|
|
260
|
+
> The transition to async `act` may prevent testing very short transient states, as awaiting `act` will flush all pending updates before returning.
|
|
261
|
+
|
|
262
|
+
**Before (v13):**
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
import { act } from '@testing-library/react-native';
|
|
266
|
+
|
|
267
|
+
it('should update state', () => {
|
|
268
|
+
act(() => {
|
|
269
|
+
setState('new value');
|
|
270
|
+
});
|
|
271
|
+
expect(state).toBe('new value');
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**After (v14):**
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { act } from '@testing-library/react-native';
|
|
279
|
+
|
|
280
|
+
it('should update state', async () => {
|
|
281
|
+
await act(() => {
|
|
282
|
+
setState('new value');
|
|
283
|
+
});
|
|
284
|
+
expect(state).toBe('new value');
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Note**: Even if your callback is synchronous, you should still use `await act(...)` as `act` now always returns a Promise.
|
|
289
|
+
|
|
290
|
+
See the [`act` API documentation](../api/other-helpers.md#act).
|
|
291
|
+
|
|
292
|
+
#### Why async APIs?
|
|
293
|
+
|
|
294
|
+
The async APIs properly handle `Suspense` boundaries and the `use()` hook, and ensure all pending React updates complete before assertions run. This matches React 19's async rendering model.
|
|
295
|
+
|
|
296
|
+
### Removed APIs
|
|
297
|
+
|
|
298
|
+
#### `update` alias removed
|
|
299
|
+
|
|
300
|
+
The `update` alias for `rerender` has been removed. Use `rerender` instead:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
// Before (v13)
|
|
304
|
+
screen.update(<MyComponent />);
|
|
305
|
+
const { update } = render(<MyComponent />);
|
|
306
|
+
update(<MyComponent newProp />);
|
|
307
|
+
|
|
308
|
+
// After (v14)
|
|
309
|
+
await screen.rerender(<MyComponent />);
|
|
310
|
+
const { rerender } = await render(<MyComponent />);
|
|
311
|
+
await rerender(<MyComponent newProp />);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### `getQueriesForElement` export removed
|
|
315
|
+
|
|
316
|
+
The `getQueriesForElement` export alias for `within` has been removed. Use `within` instead:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
// Before (v13)
|
|
320
|
+
import { getQueriesForElement } from '@testing-library/react-native';
|
|
321
|
+
|
|
322
|
+
const queries = getQueriesForElement(element);
|
|
323
|
+
|
|
324
|
+
// After (v14)
|
|
325
|
+
import { within } from '@testing-library/react-native';
|
|
326
|
+
|
|
327
|
+
const queries = within(element);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Note:** `getQueriesForElement` was just an alias for `within`, so the functionality is identical - only the import needs to change.
|
|
331
|
+
|
|
332
|
+
#### `UNSAFE_root` removed
|
|
333
|
+
|
|
334
|
+
`UNSAFE_root` has been removed. Use `container` to access the pseudo-element container, or `root` to access the first rendered host element:
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
// Before (v13)
|
|
338
|
+
const unsafeRoot = screen.UNSAFE_root;
|
|
339
|
+
|
|
340
|
+
// After (v14)
|
|
341
|
+
const container = screen.container; // pseudo-element container
|
|
342
|
+
const root = screen.root; // first rendered host element
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### Legacy `UNSAFE_*` queries removed
|
|
346
|
+
|
|
347
|
+
The legacy `UNSAFE_getAllByType`, `UNSAFE_getByType`, `UNSAFE_getAllByProps`, and `UNSAFE_getByProps` queries have been removed. These queries could return composite (user-defined) components, which is no longer supported with [Test Renderer](https://github.com/mdjastrzebski/test-renderer) as it only renders host elements.
|
|
348
|
+
|
|
349
|
+
If you were using these legacy queries, you should refactor your tests to use the standard queries (`getByRole`, `getByText`, `getByTestId`, etc.) which target host elements.
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
// Before (v13)
|
|
353
|
+
const buttons = screen.UNSAFE_getAllByType(Button);
|
|
354
|
+
const input = screen.UNSAFE_getByProps({ placeholder: 'Enter text' });
|
|
355
|
+
|
|
356
|
+
// After (v14)
|
|
357
|
+
const buttons = screen.getAllByRole('button');
|
|
358
|
+
const input = screen.getByPlaceholderText('Enter text');
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
#### `concurrentRoot` option removed
|
|
362
|
+
|
|
363
|
+
The `concurrentRoot` option has been removed from both `render` options and `configure` function. In v14, concurrent rendering is always enabled, since it's the standard rendering mode for React 19 and React Native's New Architecture.
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
// Before (v13)
|
|
367
|
+
render(<MyComponent />, { concurrentRoot: true }); // Enable concurrent mode
|
|
368
|
+
render(<MyComponent />, { concurrentRoot: false }); // Disable concurrent mode
|
|
369
|
+
configure({ concurrentRoot: false }); // Disable globally
|
|
370
|
+
|
|
371
|
+
// After (v14)
|
|
372
|
+
await render(<MyComponent />); // Always uses concurrent rendering
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Migration:** Remove any `concurrentRoot` options from your `render` calls and `configure` function. If you were setting `concurrentRoot: true`, just remove the option. If you were setting `concurrentRoot: false` to disable concurrent rendering, this is no longer supported in v14.
|
|
376
|
+
|
|
377
|
+
#### `createNodeMock` option removed
|
|
378
|
+
|
|
379
|
+
The `createNodeMock` render option has been removed. It was previously passed through to React Test Renderer, but the v14 Test Renderer integration does not support this option.
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
// Before (v13)
|
|
383
|
+
render(<MyComponent />, {
|
|
384
|
+
createNodeMock: (element) => {
|
|
385
|
+
if (element.type === TextInput) {
|
|
386
|
+
return { focus: jest.fn() };
|
|
387
|
+
}
|
|
388
|
+
return {};
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// After (v14)
|
|
393
|
+
await render(<MyComponent />);
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
If you used `createNodeMock` to mock imperative refs, prefer testing user-visible behavior and mock the component or native module at the boundary where the ref behavior is introduced.
|
|
397
|
+
|
|
398
|
+
### `container` API reintroduced
|
|
399
|
+
|
|
400
|
+
In v14, the `container` API has been reintroduced and is now safe to use. Previously, `container` was renamed to `UNSAFE_root` in v12 due to behavioral differences from React Testing Library's `container`. Now `container` returns a pseudo-element container whose children are the elements you rendered, consistent with React Testing Library's behavior.
|
|
401
|
+
|
|
402
|
+
**What changed:**
|
|
403
|
+
|
|
404
|
+
- `screen.container` is now available and safe to use
|
|
405
|
+
- `container` returns a pseudo-element container from Test Renderer
|
|
406
|
+
- The container's children are the elements you rendered
|
|
407
|
+
- `UNSAFE_root` has been removed
|
|
408
|
+
|
|
409
|
+
**Before (v13):**
|
|
410
|
+
|
|
411
|
+
```ts
|
|
412
|
+
import { render, screen } from '@testing-library/react-native';
|
|
413
|
+
|
|
414
|
+
it('should access root', () => {
|
|
415
|
+
render(<MyComponent />);
|
|
416
|
+
// UNSAFE_root was the only way to access the container
|
|
417
|
+
const root = screen.UNSAFE_root;
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**After (v14):**
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
import { render, screen } from '@testing-library/react-native';
|
|
425
|
+
|
|
426
|
+
it('should access container', async () => {
|
|
427
|
+
await render(<MyComponent />);
|
|
428
|
+
// container is now safe and available
|
|
429
|
+
const container = screen.container;
|
|
430
|
+
// root is the first child of container
|
|
431
|
+
const root = screen.root;
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
See the [`screen` API documentation](../api/screen.md#container).
|
|
436
|
+
|
|
437
|
+
### Text string validation enforced by default
|
|
438
|
+
|
|
439
|
+
In v14, Test Renderer enforces React Native's requirement that text strings must be rendered within a `<Text>` component. The `unstable_validateStringsRenderedWithinText` option has been removed from `RenderOptions` since this validation is now always on.
|
|
440
|
+
|
|
441
|
+
**What changed:**
|
|
442
|
+
|
|
443
|
+
- Text string validation is now always enabled and cannot be disabled
|
|
444
|
+
- The `unstable_validateStringsRenderedWithinText` option has been removed
|
|
445
|
+
- Tests will now throw `Invariant Violation: Text strings must be rendered within a <Text> component` errors when attempting to render strings outside of `<Text>` components, matching React Native's runtime behavior
|
|
446
|
+
|
|
447
|
+
**Migration:**
|
|
448
|
+
|
|
449
|
+
If you were using `unstable_validateStringsRenderedWithinText: true` in your render options, you can simply remove this option as the validation is now always enabled:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
// Before (v13)
|
|
453
|
+
render(<MyComponent />, {
|
|
454
|
+
unstable_validateStringsRenderedWithinText: true,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// After (v14)
|
|
458
|
+
await render(<MyComponent />);
|
|
459
|
+
// Validation is now always enabled
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
If you were relying on the previous behavior where strings could be rendered outside of `<Text>` components, you'll need to fix your components to wrap strings in `<Text>` components, as this matches React Native's actual runtime behavior.
|
|
463
|
+
|
|
464
|
+
### Hidden Suspense and Activity content
|
|
465
|
+
|
|
466
|
+
When React keeps previously rendered content hidden, such as suspended content or React 19.2 `<Activity mode="hidden">`, RNTL now applies React Native-like hidden props to the affected instances. In practice, hidden instances receive `display: 'none'`, preserving existing styles by appending the hidden style.
|
|
467
|
+
|
|
468
|
+
This makes visibility queries and matchers behave closer to runtime behavior:
|
|
469
|
+
|
|
470
|
+
- default queries do not match hidden instances
|
|
471
|
+
- queries with `{ includeHiddenElements: true }` can still find hidden instances
|
|
472
|
+
- `toBeVisible()` treats these instances as hidden
|
|
473
|
+
|
|
474
|
+
### Accessible name changes
|
|
475
|
+
|
|
476
|
+
Accessible name calculation has been updated to better match React Native behavior:
|
|
477
|
+
|
|
478
|
+
- `aria-labelledby` and `accessibilityLabelledBy` still take precedence over explicit labels
|
|
479
|
+
- `aria-label` and `accessibilityLabel` take precedence over text content
|
|
480
|
+
- `Image` `alt` is used as an accessible label
|
|
481
|
+
- a root `TextInput` can use its `placeholder` as its accessible name
|
|
482
|
+
- child accessible names are concatenated with spaces
|
|
483
|
+
- child `TextInput` placeholders are not used when computing a parent's accessible name
|
|
484
|
+
|
|
485
|
+
This affects `getByRole(..., { name })` and `toHaveAccessibleName()`. If a v13 role query matched because descendant text or label queries were used as a fallback, update the test to match the element's computed accessible name directly or query the descendant element instead.
|
|
486
|
+
|
|
487
|
+
### Unknown options now warn
|
|
488
|
+
|
|
489
|
+
RNTL now logs a warning when unknown options are passed to `configure`, `render`, `renderHook`, or `userEvent.setup`. This helps catch stale v13 options and misspellings during migration.
|
|
490
|
+
|
|
491
|
+
For example, after removing `concurrentRoot`, `createNodeMock`, or `unstable_validateStringsRenderedWithinText`, make sure those options are not still being passed through shared test helpers.
|
|
492
|
+
|
|
493
|
+
## Codemods
|
|
494
|
+
|
|
495
|
+
Two codemods are available to automate the migration. Both are safe to run multiple times - they only transform code that hasn't been migrated yet.
|
|
496
|
+
|
|
497
|
+
### `rntl-v14-update-deps`
|
|
498
|
+
|
|
499
|
+
Updates your `package.json`:
|
|
500
|
+
|
|
501
|
+
- Removes React Test Renderer (`react-test-renderer` and `@types/react-test-renderer`)
|
|
502
|
+
- Adds Test Renderer (`test-renderer`) using the current recommended 1.x line
|
|
503
|
+
- Updates `@testing-library/react-native` to the v14 version
|
|
504
|
+
|
|
505
|
+
<PackageManagerTabs
|
|
506
|
+
command={{
|
|
507
|
+
npm: 'npx codemod@latest rntl-v14-update-deps --target .\nnpm install',
|
|
508
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-update-deps --target .\nyarn install',
|
|
509
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-update-deps --target .\npnpm install',
|
|
510
|
+
bun: 'bunx codemod@latest rntl-v14-update-deps --target .\nbun install',
|
|
511
|
+
}}
|
|
512
|
+
/>
|
|
513
|
+
|
|
514
|
+
### `rntl-v14-async-functions`
|
|
515
|
+
|
|
516
|
+
Transforms test files:
|
|
517
|
+
|
|
518
|
+
- Adds `await` to `render()`, `act()`, `renderHook()`, `fireEvent()` calls
|
|
519
|
+
- Makes test functions async when needed
|
|
520
|
+
- Handles `screen.rerender()`, `screen.unmount()`, and renderer methods
|
|
521
|
+
|
|
522
|
+
<PackageManagerTabs
|
|
523
|
+
command={{
|
|
524
|
+
npm: 'npx codemod@latest rntl-v14-async-functions --target ./src',
|
|
525
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-async-functions --target ./src',
|
|
526
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-async-functions --target ./src',
|
|
527
|
+
bun: 'bunx codemod@latest rntl-v14-async-functions --target ./src',
|
|
528
|
+
}}
|
|
529
|
+
/>
|
|
530
|
+
|
|
531
|
+
#### Custom render functions
|
|
532
|
+
|
|
533
|
+
If you have custom render helpers (like `renderWithProviders`), you can specify them using the `customRenderFunctions` parameter. The codemod will then also transform calls to these functions:
|
|
534
|
+
|
|
535
|
+
<PackageManagerTabs
|
|
536
|
+
command={{
|
|
537
|
+
npm: 'npx codemod@latest rntl-v14-async-functions \\\n --target ./src \\\n --param customRenderFunctions="renderWithProviders,renderWithTheme"',
|
|
538
|
+
yarn: 'yarn dlx codemod@latest rntl-v14-async-functions \\\n --target ./src \\\n --param customRenderFunctions="renderWithProviders,renderWithTheme"',
|
|
539
|
+
pnpm: 'pnpm dlx codemod@latest rntl-v14-async-functions \\\n --target ./src \\\n --param customRenderFunctions="renderWithProviders,renderWithTheme"',
|
|
540
|
+
bun: 'bunx codemod@latest rntl-v14-async-functions \\\n --target ./src \\\n --param customRenderFunctions="renderWithProviders,renderWithTheme"',
|
|
541
|
+
}}
|
|
542
|
+
/>
|
|
543
|
+
|
|
544
|
+
This will add `await` to your custom render calls and make the containing test functions async, just like it does for the standard `render` function.
|
|
545
|
+
|
|
546
|
+
#### Limitations
|
|
547
|
+
|
|
548
|
+
- Helper functions defined in test files are not transformed by default
|
|
549
|
+
- Namespace imports (`import * as RNTL`) are not handled
|
|
550
|
+
|
|
551
|
+
## Full Changelog
|
|
552
|
+
|
|
553
|
+
https://github.com/callstack/react-native-testing-library/compare/v13.3.3...v14.0.0
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { PackageManagerTabs } from '@rspress/core/theme';
|
|
2
|
+
|
|
3
|
+
# Quick Start
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Open a Terminal in your project's folder and run:
|
|
8
|
+
|
|
9
|
+
<PackageManagerTabs
|
|
10
|
+
command={{
|
|
11
|
+
npm: 'npm install -D @testing-library/react-native',
|
|
12
|
+
yarn: 'yarn add -D @testing-library/react-native',
|
|
13
|
+
pnpm: 'pnpm add -D @testing-library/react-native',
|
|
14
|
+
bun: 'bun add -D @testing-library/react-native',
|
|
15
|
+
}}
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
This library has a peer dependency on [Test Renderer](https://github.com/mdjastrzebski/test-renderer). Make sure to install it:
|
|
19
|
+
|
|
20
|
+
<PackageManagerTabs
|
|
21
|
+
command={{
|
|
22
|
+
npm: 'npm install -D test-renderer',
|
|
23
|
+
yarn: 'yarn add -D test-renderer',
|
|
24
|
+
pnpm: 'pnpm add -D test-renderer',
|
|
25
|
+
bun: 'bun add -D test-renderer',
|
|
26
|
+
}}
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
Test Renderer has better compatibility with React 19 and improved type safety compared to the deprecated [React Test Renderer](https://reactjs.org/docs/test-renderer.html).
|
|
30
|
+
|
|
31
|
+
## Agent docs in the package
|
|
32
|
+
|
|
33
|
+
RNTL ships package-specific documentation for coding agents in `node_modules/@testing-library/react-native/docs/`.
|
|
34
|
+
Add this snippet to your project's `AGENTS.md` or `CLAUDE.md` file so agents use the docs for the installed package version:
|
|
35
|
+
|
|
36
|
+
```md
|
|
37
|
+
# React Native Testing Library in this project
|
|
38
|
+
|
|
39
|
+
This project uses `@testing-library/react-native`. Its APIs and testing conventions can differ from your training data.
|
|
40
|
+
Before writing or changing RNTL tests, read the relevant guide in
|
|
41
|
+
`node_modules/@testing-library/react-native/docs/`, starting with
|
|
42
|
+
`node_modules/@testing-library/react-native/docs/guides/llm-guidelines.md`.
|
|
43
|
+
Prefer those package docs over stale assumptions, and follow deprecation notices.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Jest matchers
|
|
47
|
+
|
|
48
|
+
RNTL automatically extends Jest with React Native-specific matchers. The only thing you need to do is to import anything from `@testing-library/react-native` which you already need to do to access the `render` function.
|
|
49
|
+
|
|
50
|
+
### ESLint plugin
|
|
51
|
+
|
|
52
|
+
Set up [`eslint-plugin-testing-library`](https://github.com/testing-library/eslint-plugin-testing-library) to avoid common Testing Library mistakes and bad practices.
|
|
53
|
+
|
|
54
|
+
Install the plugin (assuming you already have `eslint` installed & configured):
|
|
55
|
+
|
|
56
|
+
<PackageManagerTabs
|
|
57
|
+
command={{
|
|
58
|
+
npm: 'npm install -D eslint-plugin-testing-library',
|
|
59
|
+
yarn: 'yarn add -D eslint-plugin-testing-library',
|
|
60
|
+
pnpm: 'pnpm add -D eslint-plugin-testing-library',
|
|
61
|
+
bun: 'bun add -D eslint-plugin-testing-library',
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
|
|
65
|
+
Then, add this to your ESLint config (e.g., `.eslintrc.js`). Extend the `react` plugin:
|
|
66
|
+
|
|
67
|
+
```js title=.eslintrc.js
|
|
68
|
+
module.exports = {
|
|
69
|
+
overrides: [
|
|
70
|
+
{
|
|
71
|
+
// Test files only
|
|
72
|
+
files: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
|
|
73
|
+
extends: ['plugin:testing-library/react'],
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
```
|