Skip to content

Commit 371534b

Browse files
docs: improve api docs (#1535)
* docs: improve query docs * docs: tweaks
1 parent bab4097 commit 371534b

File tree

1 file changed

+143
-66
lines changed

1 file changed

+143
-66
lines changed

website/docs/Queries.md

+143-66
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,135 @@ id: api-queries
33
title: Queries
44
---
55

6-
import TOCInline from '@theme/TOCInline';
6+
Queries are one of the main building blocks for the React Native Testing Library. They enable you to find relevant elements in the element tree, which represents the your application's user interface when running under tests.
77

8-
<TOCInline toc={toc} />
8+
## Accessing queries
99

10-
## Query Variants
10+
All queries described below are accessible in two main ways: through the `screen` object or by capturing the `render` function call result.
1111

12-
> `getBy*` queries are shown by default in the [query documentation](#queries)
13-
> below.
12+
### Using `screen` object
13+
14+
```ts
15+
import { render, screen } from '@testing-library/react-native';
16+
17+
test('accessing queries using "screen" object', () => {
18+
render(...);
19+
20+
screen.getByRole("button", { name: "Start" });
21+
})
22+
```
23+
24+
The modern and recommended way of accessing queries is to use the `screen` object exported by the `@testing-library/react-native` package. This object will contain methods of all available queries bound to the most recently rendered UI.
25+
26+
### Using `render` result
27+
28+
```ts
29+
import { render } from '@testing-library/react-native';
30+
31+
test('accessing queries using "render" result', () => {
32+
const { getByRole } = render(...);
33+
getByRole("button", { name: "Start" });
34+
})
35+
```
36+
37+
The classic way is to capture query functions, as they are returned from the `render` function call. This provides access to the same functions as in the case of the `screen` object.
38+
39+
## Query parts
40+
41+
Each query is composed of two parts: variant and predicate, which are separated by the `by` word in the middle of the name.
42+
43+
Consider the following query:
44+
45+
```
46+
getByRole()
47+
```
48+
49+
For this query, `getBy*` is the query variant, and `*ByRole` is the predicate.
50+
51+
## Query variant
52+
53+
The query variants describe the expected number (and timing) of matching elements, so they differ in their return type.
54+
55+
| Variant | Assertion | Return type | Is Async? |
56+
| ----------------------------------------- | ----------------------------- | ------------------------------------------ | --------- |
57+
| [`getBy*`](api-queries#get-by) | Exactly one matching element | `ReactTestInstance` | No |
58+
| [`getAllBy*`](api-queries#get-all-by) | At least one matching element | `Array<ReactTestInstance>` | No |
59+
| [`queryBy*`](api-queries#query-by) | Zero or one matching element | <code>ReactTestInstance &#124; null</code> | No |
60+
| [`queryAllBy*`](api-queries#query-all-by) | No assertion | `Array<ReactTestInstance>` | No |
61+
| [`findBy*`](api-queries#find-by) | Exactly one matching element | `Promise<ReactTestInstance>` | Yes |
62+
| [`findAllBy*`](api-queries#find-all-by) | At least one matching element | `Promise<Array<ReactTestInstance>>` | Yes |
63+
64+
Queries work as implicit assertions on the number of matching elements and will throw an error when the assertion fails.
1465

1566
### `getBy*` queries {#get-by}
1667

17-
`getBy*` queries return the first matching node for a query, and throw an error if no elements match or if more than one match is found. If you need to find more than one element, then use `getAllBy`.
68+
```ts
69+
getByX(...): ReactTestInstance
70+
```
71+
72+
`getBy*` queries return the single matching element for a query, and throw an error if no elements match or if more than one match is found. If you need to find more than one element, then use `getAllBy`.
1873

1974
### `getAllBy*` queries {#get-all-by}
2075

21-
`getAllBy*` queries return an array of all matching nodes for a query, and throw an error if no elements match.
76+
```ts
77+
getAllByX(...): ReactTestInstance[]
78+
```
79+
80+
`getAllBy*` queries return an array of all matching elements for a query and throw an error if no elements match.
2281

2382
### `queryBy*` queries {#query-by}
2483

84+
```ts
85+
queryByX(...): ReactTestInstance | null
86+
```
87+
2588
`queryBy*` queries return the first matching node for a query, and return `null` if no elements match. This is useful for asserting an element that is not present. This throws if more than one match is found (use `queryAllBy` instead).
2689

2790
### `queryAllBy*` queries {#query-all-by}
2891

29-
`queryAllBy*` queries return an array of all matching nodes for a query, and return an empty array (`[]`) when no elements match.
92+
```ts
93+
queryAllByX(...): ReactTestInstance[]
94+
```
95+
96+
`queryAllBy*` queries return an array of all matching nodes for a query and return an empty array (`[]`) when no elements match.
3097

3198
### `findBy*` queries {#find-by}
3299

33-
`findBy*` queries return a promise which resolves when a matching element is found. The promise is rejected if no elements match or if more than one match is found after a default timeout of 1000 ms. If you need to find more than one element, then use `findAllBy*`.
100+
```ts
101+
findByX(
102+
...,
103+
waitForOptions?: {
104+
timeout?: number,
105+
interval?: number,
106+
},
107+
): Promise<ReactTestInstance>
108+
```
109+
110+
`findBy*` queries return a promise which resolves when a matching element is found. The promise is rejected if no elements match or if more than one match is found after a default timeout of 1000 ms. If you need to find more than one element use `findAllBy*` queries.
34111

35112
### `findAllBy*` queries {#find-all-by}
36113

37-
`findAllBy*` queries return a promise which resolves to an array of matching elements. The promise is rejected if no elements match after a default timeout of 1000 ms.
114+
```ts
115+
findAllByX(
116+
...,
117+
waitForOptions?: {
118+
timeout?: number,
119+
interval?: number,
120+
},
121+
): Promise<ReactTestInstance[]>
122+
```
38123

39-
:::info
40-
`findBy*` and `findAllBy*` queries accept optional `waitForOptions` object argument which can contain `timeout`, `interval` and `onTimeout` properies which have the same meaning as respective options for [`waitFor`](api#waitfor) function.
41-
:::
124+
`findAllBy*` queries return a promise which resolves to an array of matching elements. The promise is rejected if no elements match after a default timeout of 1000 ms.
42125

43126
:::info
44-
In cases when your `findBy*` and `findAllBy*` queries throw when not able to find matching elements it is useful to pass `onTimeout: () => { screen.debug(); }` callback using `waitForOptions` parameter.
127+
`findBy*` and `findAllBy*` queries accept optional `waitForOptions` object arguments, which can contain `timeout`, `interval` and `onTimeout` properties which have the same meaning as respective options for [`waitFor`](api#waitfor) function.
45128
:::
46129

47130
:::info
48-
In order to properly use `findBy*` and `findAllBy*` queries you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0).
131+
In cases when your `findBy*` and `findAllBy*` queries throw when unable to find matching elements, it is helpful to pass `onTimeout: () => { screen.debug(); }` callback using the `waitForOptions` parameter.
49132
:::
50133

51-
## Query Predicates
134+
## Query predicates
52135

53136
_Note: most methods like this one return a [`ReactTestInstance`](https://reactjs.org/docs/test-renderer.html#testinstance) with following properties that you may be interested in:_
54137

@@ -61,7 +144,7 @@ type ReactTestInstance = {
61144
};
62145
```
63146

64-
### `ByRole` {#by-role}
147+
### `*ByRole` {#by-role}
65148

66149
> getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole
67150
@@ -144,33 +227,34 @@ const element3 = screen.getByRole('button', { name: 'Hello', disabled: true });
144227
- See React Native [accessibilityValue](https://reactnative.dev/docs/accessibility#accessibilityvalue) docs to learn more about the accessibility value concept.
145228
- This option can alternatively be expressed using the [`toHaveAccessibilityValue()`](jest-matchers#tohaveaccessibilityvalue) Jest matcher.
146229

147-
### `ByText` {#by-text}
230+
### `*ByLabelText` {#by-label-text}
148231

149-
> getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText
232+
> getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText
150233
151234
```ts
152-
getByText(
235+
getByLabelText(
153236
text: TextMatch,
154237
options?: {
155238
exact?: boolean;
156239
normalizer?: (text: string) => string;
157240
includeHiddenElements?: boolean;
158-
}
241+
},
159242
): ReactTestInstance;
160243
```
161244

162-
Returns a `ReactTestInstance` with matching text – may be a string or regular expression.
245+
Returns a `ReactTestInstance` with matching label:
163246

164-
This method will join `<Text>` siblings to find matches, similarly to [how React Native handles these components](https://reactnative.dev/docs/text#containers). This will allow for querying for strings that will be visually rendered together, but may be semantically separate React components.
247+
- either by matching [`aria-label`](https://reactnative.dev/docs/accessibility#aria-label)/[`accessibilityLabel`](https://reactnative.dev/docs/accessibility#accessibilitylabel) prop
248+
- or by matching text content of view referenced by [`aria-labelledby`](https://reactnative.dev/docs/accessibility#aria-labelledby-android)/[`accessibilityLabelledBy`](https://reactnative.dev/docs/accessibility#accessibilitylabelledby-android) prop
165249

166250
```jsx
167251
import { render, screen } from '@testing-library/react-native';
168252

169253
render(<MyComponent />);
170-
const element = screen.getByText('banana');
254+
const element = screen.getByLabelText('my-label');
171255
```
172256

173-
### `ByPlaceholderText` {#by-placeholder-text}
257+
### `*ByPlaceholderText` {#by-placeholder-text}
174258

175259
> getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText
176260
@@ -194,7 +278,7 @@ render(<MyComponent />);
194278
const element = screen.getByPlaceholderText('username');
195279
```
196280

197-
### `ByDisplayValue` {#by-display-value}
281+
### `*ByDisplayValue` {#by-display-value}
198282

199283
> getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue
200284
@@ -218,41 +302,41 @@ render(<MyComponent />);
218302
const element = screen.getByDisplayValue('username');
219303
```
220304

221-
### `ByTestId` {#by-test-id}
305+
### `*ByText` {#by-text}
222306

223-
> getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId
307+
> getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText
224308
225309
```ts
226-
getByTestId(
227-
testId: TextMatch,
310+
getByText(
311+
text: TextMatch,
228312
options?: {
229313
exact?: boolean;
230314
normalizer?: (text: string) => string;
231315
includeHiddenElements?: boolean;
232-
},
316+
}
233317
): ReactTestInstance;
234318
```
235319

236-
Returns a `ReactTestInstance` with matching `testID` prop. `testID` – may be a string or a regular expression.
320+
Returns a `ReactTestInstance` with matching text – may be a string or regular expression.
321+
322+
This method will join `<Text>` siblings to find matches, similarly to [how React Native handles these components](https://reactnative.dev/docs/text#containers). This will allow for querying for strings that will be visually rendered together, but may be semantically separate React components.
237323

238324
```jsx
239325
import { render, screen } from '@testing-library/react-native';
240326

241327
render(<MyComponent />);
242-
const element = screen.getByTestId('unique-id');
328+
const element = screen.getByText('banana');
243329
```
244330

245-
:::info
246-
In the spirit of [the guiding principles](https://testing-library.com/docs/guiding-principles), it is recommended to use this only after the other queries don't work for your use case. Using `testID` attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post ["Making your UI tests resilient to change"](https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change).
247-
:::
331+
### `*ByHintText` {#by-hint-text}
248332

249-
### `ByLabelText` {#by-label-text}
250-
251-
> getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText
333+
> getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint
334+
> getByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint
335+
> getByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText
252336
253337
```ts
254-
getByLabelText(
255-
text: TextMatch,
338+
getByHintText(
339+
hint: TextMatch,
256340
options?: {
257341
exact?: boolean;
258342
normalizer?: (text: string) => string;
@@ -261,27 +345,26 @@ getByLabelText(
261345
): ReactTestInstance;
262346
```
263347

264-
Returns a `ReactTestInstance` with matching label:
265-
266-
- either by matching [`aria-label`](https://reactnative.dev/docs/accessibility#aria-label)/[`accessibilityLabel`](https://reactnative.dev/docs/accessibility#accessibilitylabel) prop
267-
- or by matching text content of view referenced by [`aria-labelledby`](https://reactnative.dev/docs/accessibility#aria-labelledby-android)/[`accessibilityLabelledBy`](https://reactnative.dev/docs/accessibility#accessibilitylabelledby-android) prop
348+
Returns a `ReactTestInstance` with matching `accessibilityHint` prop.
268349

269350
```jsx
270351
import { render, screen } from '@testing-library/react-native';
271352

272353
render(<MyComponent />);
273-
const element = screen.getByLabelText('my-label');
354+
const element = screen.getByHintText('Plays a song');
274355
```
275356

276-
### `ByHintText`, `ByA11yHint`, `ByAccessibilityHint` {#by-hint-text}
357+
:::info
358+
Please consult [Apple guidelines on how `accessibilityHint` should be used](https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint).
359+
:::
277360

278-
> getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint
279-
> getByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint
280-
> getByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText
361+
### `*ByTestId` {#by-test-id}
362+
363+
> getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId
281364
282365
```ts
283-
getByHintText(
284-
hint: TextMatch,
366+
getByTestId(
367+
testId: TextMatch,
285368
options?: {
286369
exact?: boolean;
287370
normalizer?: (text: string) => string;
@@ -290,20 +373,20 @@ getByHintText(
290373
): ReactTestInstance;
291374
```
292375

293-
Returns a `ReactTestInstance` with matching `accessibilityHint` prop.
376+
Returns a `ReactTestInstance` with matching `testID` prop. `testID` – may be a string or a regular expression.
294377

295378
```jsx
296379
import { render, screen } from '@testing-library/react-native';
297380

298381
render(<MyComponent />);
299-
const element = screen.getByHintText('Plays a song');
382+
const element = screen.getByTestId('unique-id');
300383
```
301384

302385
:::info
303-
Please consult [Apple guidelines on how `accessibilityHint` should be used](https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint).
386+
In the spirit of [the guiding principles](https://testing-library.com/docs/guiding-principles), it is recommended to use this only after the other queries don't work for your use case. Using `testID` attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post ["Making your UI tests resilient to change"](https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change).
304387
:::
305388

306-
### `ByA11yState`, `ByAccessibilityState` (deprecated) {#by-accessibility-state}
389+
### `*ByA11yState`, `ByAccessibilityState` (deprecated) {#by-accessibility-state}
307390

308391
:::caution
309392
This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:
@@ -373,14 +456,15 @@ but will not match elements with following props:
373456
The difference in handling default values is made to reflect observed accessibility behaviour on iOS and Android platforms.
374457
:::
375458

376-
### `ByA11yValue`, `ByAccessibilityValue` (deprecated) {#by-accessibility-value}
459+
### `*ByA11yValue`, `*ByAccessibilityValue` (deprecated) {#by-accessibility-value}
377460

378461
:::caution
379462
This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:
380463

381464
- [`toHaveAccessibilityValue()`](jest-matchers#tohaveaccessibilityvalue) Jest matcher to check the state of element found using some other query
382465
- [`*ByRole`](#by-role) query with `value` option
383-
:::
466+
467+
:::
384468

385469
> getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue
386470
> getByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue
@@ -540,12 +624,7 @@ screen.getByText(node, 'text', {
540624

541625
## Legacy unit testing helpers
542626

543-
> Use sparingly and responsibly, escape hatches here
544-
545-
`render` from `@testing-library/react-native` exposes additional queries that **should not be used in component integration testing**, but some users (like component library creators) interested in unit testing some components may find helpful.
546-
547-
<details>
548-
<summary>Queries helpful in unit testing</summary>
627+
`render` from `@testing-library/react-native` exposes additional queries that **should not be used in integration or component testing**, but some users (like component library creators) interested in unit testing some components may find helpful.
549628

550629
The interface is the same as for other queries, but we won't provide full names so that they're harder to find by search engines.
551630

@@ -568,5 +647,3 @@ Returns a `ReactTestInstance` with matching props object.
568647
:::caution
569648
This query has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.
570649
:::
571-
572-
</details>

0 commit comments

Comments
 (0)