Skip to content

Commit 84ba56e

Browse files
docs: Jest matchers docs (#1506)
* docs: v1 of jest matchers docs * chore: add TOC * chore: tweak heading levels * docs: tweaks * docs: cross references * docs: tweaks * docs: tweaks * docs: tweaks * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/JestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/MigrationJestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * Update website/docs/MigrationJestMatchers.md Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com> * docs: spellchecking * chore: final fixes --------- Co-authored-by: Pierre Zimmermann <64224599+pierrezimmermannbam@users.noreply.github.com>
1 parent 2ada536 commit 84ba56e

File tree

4 files changed

+315
-19
lines changed

4 files changed

+315
-19
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
## The problem
2222

23-
You want to write maintainable tests for your React Native components. As a part of this goal, you want your tests to avoid including implementation details of your components and rather focus on making your tests give you the confidence for which they are intended. As part of this, you want your testbase to be maintainable in the long run so refactors of your components (changes to implementation but not functionality) don't break your tests and slow you and your team down.
23+
You want to write maintainable tests for your React Native components. As a part of this goal, you want your tests to avoid including implementation details of your components and rather focus on making your tests give you the confidence for which they are intended. As part of this, you want your tests to be maintainable in the long run so refactors of your components (changes to implementation but not functionality) don't break your tests and slow you and your team down.
2424

2525
## This solution
2626

@@ -50,7 +50,7 @@ This library has a `peerDependencies` listing for `react-test-renderer`. Make su
5050

5151
### Additional Jest matchers
5252

53-
In order to use additional React Native-specific jest matchers from [@testing-library/jest-native](https://github.com/testing-library/jest-native) package add it to your project:
53+
To use additional React Native-specific jest matchers from [@testing-library/jest-native](https://github.com/testing-library/jest-native) package add it to your project:
5454

5555
#### Using `yarn`
5656

@@ -64,7 +64,7 @@ yarn add --dev @testing-library/jest-native
6464
npm install --save-dev @testing-library/jest-native
6565
```
6666

67-
Then automatically add it to your jest tests by using `setupFilesAfterEnv` option in your Jest configuration (it's usually located either in `package.json` under `"jest"` key or in a `jest.config.json` file):
67+
Then automatically add it to your jest tests by using the `setupFilesAfterEnv` option in your Jest configuration (it's usually located either in `package.json` under the `"jest"` key or in a `jest.config.json` file):
6868

6969
```json
7070
{
@@ -75,9 +75,9 @@ Then automatically add it to your jest tests by using `setupFilesAfterEnv` optio
7575

7676
### Custom Jest Preset (React Native before 0.71)
7777

78-
We generally advise to use the "react-native" preset when testing with this library.
78+
We generally advise using the "react-native" preset when testing with this library.
7979

80-
However, if you use React Native version earlier than 0.71 with [modern Jest fake timers](https://jestjs.io/blog/2020/05/05/jest-26#new-fake-timers) (default since Jest 27), you'll need to apply this custom Jest preset or otherwise awaiting promises, like using `waitFor` or `findBy*`, queries will fail with timeout.
80+
However, if you use React Native version earlier than 0.71 with [modern Jest fake timers](https://jestjs.io/blog/2020/05/05/jest-26#new-fake-timers) (default since Jest 27), you'll need to apply this custom Jest preset or otherwise awaiting promises, like using `waitFor` or `findBy*`, queries will fail with a timeout.
8181

8282
This is a [known issue](https://github.com/facebook/react-native/issues/29303). It happens because React Native's Jest preset overrides native Promise. Our preset restores it to defaults, which is not a problem in most apps out there.
8383

@@ -130,11 +130,11 @@ You can find the source of `QuestionsBoard` component and this example [here](ht
130130

131131
The [public API](https://callstack.github.io/react-native-testing-library/docs/api) of `@testing-library/react-native` is focused around these essential methods:
132132

133-
- [`render`](https://callstack.github.io/react-native-testing-library/docs/api#render) – deeply renders given React element and returns helpers to query the output components.
133+
- [`render`](https://callstack.github.io/react-native-testing-library/docs/api#render) – deeply renders the given React element and returns helpers to query the output components.
134134
- [`fireEvent`](https://callstack.github.io/react-native-testing-library/docs/api#fireevent) - invokes named event handler on the element.
135-
- [`waitFor`](https://callstack.github.io/react-native-testing-library/docs/api#waitfor) - waits for non-deterministic periods of time until queried element is added or times out.
136-
- [`waitForElementToBeRemoved`](https://callstack.github.io/react-native-testing-library/docs/api#waitforelementtoberemoved) - waits for non-deterministic periods of time until queried element is removed or times out.
137-
- [`within`](https://callstack.github.io/react-native-testing-library/docs/api#within) - creates a queries object scoped for given element.
135+
- [`waitFor`](https://callstack.github.io/react-native-testing-library/docs/api#waitfor) - waits for non-deterministic periods of time until the queried element is added or times out.
136+
- [`waitForElementToBeRemoved`](https://callstack.github.io/react-native-testing-library/docs/api#waitforelementtoberemoved) - waits for non-deterministic periods of time until the queried element is removed or times out.
137+
- [`within`](https://callstack.github.io/react-native-testing-library/docs/api#within) - creates a queries object scoped for a given element.
138138

139139
## Migration Guides
140140

@@ -150,7 +150,7 @@ The [public API](https://callstack.github.io/react-native-testing-library/docs/a
150150

151151
## Related External Resources
152152

153-
- [Real world extensive examples repo](https://github.com/vanGalilea/react-native-testing)
153+
- [Real-world extensive examples repo](https://github.com/vanGalilea/react-native-testing)
154154
- [Where and how to start testing 🧪 your react-native app ⚛️ and how to keep on testin’](https://blog.usejournal.com/where-and-how-to-start-testing-your-react-native-app-%EF%B8%8F-and-how-to-keep-on-testin-ec3464fb9b41)
155155
- [Intro to React Native Testing Library & Jest Native](https://youtu.be/CpTQb0XWlRc)
156156

website/docs/JestMatchers.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
---
2+
id: jest-matchers
3+
title: Jest Matchers
4+
---
5+
6+
:::note
7+
Built-in Jest matchers require RNTL v12.4.0 or later.
8+
:::
9+
10+
This guide describes built-in Jest matchers, we recommend using these matchers as they provide more readable tests, better accessibility support, and a better developer experience.
11+
12+
If you are already using legacy Jest Native matchers we have a [migration guide](migration-jest-native) for moving to the built-in matchers.
13+
14+
import TOCInline from '@theme/TOCInline';
15+
16+
<TOCInline toc={toc} />
17+
18+
## Element Existence
19+
20+
### `toBeOnTheScreen()`
21+
22+
```ts
23+
expect(element).toBeOnTheScreen()
24+
```
25+
26+
This allows you to assert whether an element is attached to the element tree or not. If you hold a reference to an element and it gets unmounted during the test it will no longer pass this assertion.
27+
28+
## Element Content
29+
30+
### `toHaveTextContent()`
31+
32+
```ts
33+
expect(element).toHaveTextContent(
34+
text: string | RegExp,
35+
options?: {
36+
exact?: boolean;
37+
normalizer?: (text: string) => string;
38+
},
39+
)
40+
```
41+
42+
This allows you to assert whether the given element has the given text content or not. It accepts either `string` or `RegExp` matchers, as well as [text match options](Queries.md#text-match-options) of `exact` and `normalizer`.
43+
44+
### `toContainElement()`
45+
46+
```ts
47+
expect(container).toContainElement(
48+
element: ReactTestInstance | null,
49+
)
50+
```
51+
52+
This allows you to assert whether the given container element does contain another host element.
53+
54+
### `toBeEmptyElement()`
55+
56+
```ts
57+
expect(element).toBeEmptyElement()
58+
```
59+
60+
This allows you to assert whether the given element does not have any host child elements or text content.
61+
62+
63+
64+
65+
66+
## Element State
67+
68+
### `toHaveDisplayValue()`
69+
70+
```ts
71+
expect(element).toHaveDisplayValue(
72+
value: string | RegExp,
73+
options?: {
74+
exact?: boolean;
75+
normalizer?: (text: string) => string;
76+
},
77+
)
78+
```
79+
80+
This allows you to assert whether the given `TextInput` element has a specified display value. It accepts either `string` or `RegExp` matchers, as well as [text match options](Queries.md#text-match-options) of `exact` and `normalizer`.
81+
82+
### `toHaveAccessibilityValue()`
83+
84+
```ts
85+
expect(element).toHaveAccessibilityValue(
86+
value: {
87+
min?: number;
88+
max?: number;
89+
now?: number;
90+
text?: string | RegExp;
91+
},
92+
)
93+
```
94+
95+
This allows you to assert whether the given element has a specified accessible value.
96+
97+
This matcher will assert accessibility value based on `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, `aria-valuetext` and `accessibilityValue` props. Only defined value entries will be used in the assertion, the element might have additional accessibility value entries and still be matched.
98+
99+
When querying by `text` entry a string or `RegExp` might be used.
100+
101+
102+
### `toBeEnabled()` / `toBeDisabled` {#tobeenabled}
103+
104+
```ts
105+
expect(element).toBeEnabled()
106+
expect(element).toBeDisabled()
107+
```
108+
109+
These allow you to assert whether the given element is enabled or disabled from the user's perspective. It relies on the accessibility disabled state as set by `aria-disabled` or `accessibilityState.disabled` props. It will consider a given element disabled when it or any of its ancestors is disabled.
110+
111+
:::note
112+
These matchers are the negation of each other, and both are provided to avoid double negations in your assertions.
113+
:::
114+
115+
116+
### `toBeSelected()`
117+
118+
```ts
119+
expect(element).toBeSelected()
120+
```
121+
122+
This allows you to assert whether the given element is selected from the user's perspective. It relies on the accessibility selected state as set by `aria-selected` or `accessibilityState.selected` props.
123+
124+
125+
### `toBeChecked()` / `toBePartiallyChecked()` {#tobechecked}
126+
127+
```ts
128+
expect(element).toBeChecked()
129+
expect(element).toBePartiallyChecked()
130+
```
131+
132+
These allow you to assert whether the given element is checked or partially checked from the user's perspective. It relies on the accessibility checked state as set by `aria-checked` or `accessibilityState.checked` props.
133+
134+
:::note
135+
* `toBeChecked()` matcher works only on elements with the `checkbox` or `radio` role.
136+
* `toBePartiallyChecked()` matcher works only on elements with the `checkbox` role.
137+
:::
138+
139+
### `toBeExpanded()` / `toBeCollapsed()` {#tobeexpanded}
140+
141+
```ts
142+
expect(element).toBeExpanded()
143+
expect(element).toBeCollapsed()
144+
```
145+
146+
These allows you to assert whether the given element is expanded or collapsed from the user's perspective. It relies on the accessibility disabled state as set by `aria-expanded` or `accessibilityState.expanded` props.
147+
148+
:::note
149+
These matchers are the negation of each other for expandable elements (elements with explicit `aria-expanded` or `accessibilityState.expanded` props). However, both won't pass for non-expandable elements (ones without explicit `aria-expanded` or `accessibilityState.expanded` props).
150+
:::
151+
152+
153+
### `toBeBusy()`
154+
155+
```ts
156+
expect(element).toBeBusy()
157+
```
158+
159+
This allows you to assert whether the given element is busy from the user's perspective. It relies on the accessibility selected state as set by `aria-busy` or `accessibilityState.busy` props.
160+
161+
## Element Styles
162+
163+
### `toBeVisible()`
164+
165+
```ts
166+
expect(element).toBeVisible()
167+
```
168+
169+
This allows you to assert whether the given element is visible from the user's perspective.
170+
171+
The element is considered invisible when itself or any of its ancestors has `display: none` or `opacity: 0` styles, as well as when it's hidden from accessibility.
172+
173+
### `toHaveStyle()`
174+
175+
```ts
176+
expect(element).toHaveStyle(
177+
style: StyleProp<Style>,
178+
)
179+
```
180+
181+
This allows you to assert whether the given element has given styles.
182+
183+
## Other
184+
185+
### `toHaveAccessibleName()`
186+
187+
```ts
188+
expect(element).toHaveAccessibleName(
189+
name?: string | RegExp,
190+
options?: {
191+
exact?: boolean;
192+
normalizer?: (text: string) => string;
193+
},
194+
)
195+
```
196+
197+
This allows you to assert whether the given element has a specified accessible name. It accepts either `string` or `RegExp` matchers, as well as [text match options](Queries.md#text-match-options) of `exact` and `normalizer`.
198+
199+
The accessible name will be computed based on `aria-labelledby`, `accessibilityLabelledBy`, `aria-label`, and `accessibilityLabel` props, in the absence of these props, the element text content will be used.
200+
201+
When the `name` parameter is `undefined` it will only check if the element has any accessible name.
202+
203+
### `toHaveProp()`
204+
205+
```ts
206+
expect(element).toHaveProp(
207+
name: string,
208+
value?: unknown,
209+
)
210+
```
211+
212+
This allows you to assert whether the given element has a given prop. When the `value` parameter is `undefined` it will only check for existence of the prop, and when `value` is defined it will check if the actual value matches passed value.
213+
214+
:::note
215+
This matcher should be treated as an escape hatch to be used when all other matchers are not suitable.
216+
:::

website/docs/MigrationJestMatchers.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
id: migration-jest-native
3+
title: Migration from Jest Native matchers
4+
---
5+
6+
This guide describes the steps necessary to migrate from [legacy Jest Native matchers v5](https://github.com/testing-library/jest-native) to [built-in Jest matchers](jest-matchers).
7+
8+
import TOCInline from '@theme/TOCInline';
9+
10+
<TOCInline toc={toc} />
11+
12+
## General notes
13+
14+
All of the built-in Jest matchers provided by the React Native Testing Library support only host elements. This should not be an issue, as all RNTL v12 queries already return only host elements. When this guide states that a given matcher should work the same it assumes behavior only host elements. If you need to assert the status of composite elements use Jest Native matchers in [legacy mode](#gradual-migration).
15+
16+
## Usage
17+
18+
You can use the built-in matchers by adding the following line to your `jest-setup.ts` file:
19+
20+
```ts
21+
import '@testing-library/react-native/extend-expect';
22+
```
23+
24+
### Gradual migration
25+
26+
You can use the built-in matchers alongside legacy Jest Native matchers by changing their import in your `jest-setup.ts` file:
27+
28+
```ts
29+
// Replace this:
30+
// import '@testing-library/jest-native/extend-expect';
31+
32+
// With this:
33+
import '@testing-library/react-native/extend-expect';
34+
import '@testing-library/jest-native/legacy-extend-expect';
35+
```
36+
37+
In this case legacy matchers will be available using the `legacy_` prefix, e.g.:
38+
39+
```ts
40+
expect(element).legacy_toHaveAccessibilityState({ busy: true });
41+
```
42+
43+
## Migration details
44+
45+
### Matchers not requiring changes
46+
47+
The following matchers should work the same:
48+
* [`toBeEmptyElement()`](jest-matchers#tobeemptyelement)
49+
* [`toBeEnabled()` / `toBeDisabled()`](jest-matchers#tobeenabled)
50+
* [`toBeOnTheScreen()`](jest-matchers#tobeonthescreen)
51+
* [`toBeVisible()`](jest-matchers#tobevisible)
52+
* [`toContainElement()`](jest-matchers#tocontainelement)
53+
* [`toHaveAccessibilityValue()`](jest-matchers#tohaveaccessibilityvalue)
54+
* [`toHaveDisplayValue()`](jest-matchers#tohavedisplayvalue)
55+
* [`toHaveProp()`](jest-matchers#tohaveprop)
56+
* [`toHaveStyle()`](jest-matchers#tohavestyle)
57+
* [`toHaveTextContent()`](jest-matchers#tohavetextcontent)
58+
59+
### Replaced matchers
60+
61+
The `toHaveAccessibilityState()` matcher has been replaced by the following matchers:
62+
* enabled state: [`toBeEnabled()` / `toBeDisabled()`](jest-matchers#tobeenabled)
63+
* checked state: [`toBeChecked()` / `toBePartiallyChecked()`](jest-matchers#tobechecked)
64+
* selected state: [`toBeSelected()`](jest-matchers#tobeselected)
65+
* expanded state: [`toBeExpanded()` / `toBeCollapsed()`](jest-matchers#tobeexpanded)
66+
* busy state: [`toBeBusy()`](jest-matchers#tobebusy)
67+
68+
The new matchers support both `accessibilityState` and `aria-*` props.
69+
70+
### Added matchers
71+
72+
New [`toHaveAccessibleName()`](jest-matchers#tohaveaccessiblename) has been added.
73+
74+
### Noteworthy details
75+
76+
You should be aware of the following details:
77+
* [`toBeEnabled()` / `toBeDisabled()`](jest-matchers#tobeenabled) matchers also check the disabled state for the element's ancestors and not only the element itself. This is the same as in legacy Jest Native matchers of the same name but differs from the removed `toHaveAccessibilityState()` matcher.
78+
* [`toBeChecked()`](jest-matchers#tobechecked) matcher supports only elements with a `checkbox` or `radio` role
79+
* [`toBePartiallyChecked()`](jest-matchers#tobechecked) matcher supports only elements with `checkbox` role

0 commit comments

Comments
 (0)