Skip to content

Commit 8be8bf9

Browse files
author
Sunil Pai
authored
Testing Docs (reactjs#2165)
* Testing Docs This expands the testing docs for reactjs.org. It adds 3 main docs - - testing.md: An entry point to the testing docs - testing-recipes.md: Common patterns when writing tests for React Components. - testing-environments.md: Setting up your testing environment. With help from @alexkrolick, @kentcdodds, @gaearon
1 parent 4867765 commit 8be8bf9

File tree

10 files changed

+739
-20
lines changed

10 files changed

+739
-20
lines changed

content/blog/2019-02-06-react-v16.8.0.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Even while Hooks were in alpha, the React community created many interesting [ex
5050

5151
## Testing Hooks {#testing-hooks}
5252

53-
We have added a new API called `ReactTestUtils.act()` in this release. It ensures that the behavior in your tests matches what happens in the browser more closely. We recommend to wrap any code rendering and triggering updates to your components into `act()` calls. Testing libraries can also wrap their APIs with it (for example, [`react-testing-library`](https://github.com/kentcdodds/react-testing-library)'s `render` and `fireEvent` utilities do this).
53+
We have added a new API called `ReactTestUtils.act()` in this release. It ensures that the behavior in your tests matches what happens in the browser more closely. We recommend to wrap any code rendering and triggering updates to your components into `act()` calls. Testing libraries can also wrap their APIs with it (for example, [`react-testing-library`](https://testing-library.com/react)'s `render` and `fireEvent` utilities do this).
5454

5555
For example, the counter example from [this page](/docs/hooks-effect.html) can be tested like this:
5656

@@ -95,7 +95,7 @@ The calls to `act()` will also flush the effects inside of them.
9595

9696
If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote.
9797

98-
To reduce the boilerplate, we recommend using [`react-testing-library`](https://git.io/react-testing-library) which is designed to encourage writing tests that use your components as the end users do.
98+
To reduce the boilerplate, we recommend using [`react-testing-library`](https://testing-library.com/react) which is designed to encourage writing tests that use your components as the end users do.
9999

100100
## Thanks {#thanks}
101101

content/community/nav.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
title: Model Management
3535
- id: data-fetching
3636
title: Data Fetching
37-
- id: testing
38-
title: Testing
3937
- id: ui-components
4038
title: UI Components
4139
- id: misc

content/community/tools-testing.md

Lines changed: 0 additions & 13 deletions
This file was deleted.

content/docs/addons-test-utils.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ it('can render and update a counter', () => {
122122
});
123123
```
124124

125-
Don't forget that dispatching DOM events only works when the DOM container is added to the `document`. You can use a helper like [`react-testing-library`](https://github.com/kentcdodds/react-testing-library) to reduce the boilerplate code.
125+
- Don't forget that dispatching DOM events only works when the DOM container is added to the `document`. You can use a library like [React Testing Library](https://testing-library.com/react) to reduce the boilerplate code.
126+
127+
- The [`recipes`](/docs/recipes.html) document contains more details on how `act()` behaves, with examples and usage.
126128

127129
* * *
128130

@@ -139,7 +141,7 @@ Pass a mocked component module to this method to augment it with useful methods
139141

140142
> Note:
141143
>
142-
> `mockComponent()` is a legacy API. We recommend using [shallow rendering](/docs/shallow-renderer.html) or [`jest.mock()`](https://facebook.github.io/jest/docs/en/tutorial-react-native.html#mock-native-modules-using-jestmock) instead.
144+
> `mockComponent()` is a legacy API. We recommend using [`jest.mock()`](https://facebook.github.io/jest/docs/en/tutorial-react-native.html#mock-native-modules-using-jestmock) instead.
143145
144146
* * *
145147

content/docs/hooks-faq.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ The calls to `act()` will also flush the effects inside of them.
180180

181181
If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote.
182182

183-
To reduce the boilerplate, we recommend using [`react-testing-library`](https://git.io/react-testing-library) which is designed to encourage writing tests that use your components as the end users do.
183+
To reduce the boilerplate, we recommend using [React Testing Library](https://testing-library.com/react) which is designed to encourage writing tests that use your components as the end users do.
184184

185185
### What exactly do the [lint rules](https://www.npmjs.com/package/eslint-plugin-react-hooks) enforce? {#what-exactly-do-the-lint-rules-enforce}
186186

content/docs/nav.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@
125125
title: Hooks API Reference
126126
- id: hooks-faq
127127
title: Hooks FAQ
128+
- title: Testing
129+
items:
130+
- id: testing
131+
title: Testing Overview
132+
- id: testing-recipes
133+
title: Testing Recipes
134+
- id: testing-environments
135+
title: Testing Environments
128136
- title: Contributing
129137
items:
130138
- id: how-to-contribute

content/docs/reference-test-renderer.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);
7070
### TestRenderer {#testrenderer}
7171

7272
* [`TestRenderer.create()`](#testrenderercreate)
73+
* [`TestRenderer.act()`](#testrendereract)
7374

7475
### TestRenderer instance {#testrenderer-instance}
7576

@@ -104,6 +105,36 @@ TestRenderer.create(element, options);
104105

105106
Create a `TestRenderer` instance with the passed React element. It doesn't use the real DOM, but it still fully renders the component tree into memory so you can make assertions about it. The returned instance has the following methods and properties.
106107

108+
### `TestRenderer.act()` {#testrendereract}
109+
110+
```javascript
111+
TestRenderer.act(callback);
112+
```
113+
114+
Similar to the [`act()` helper from `react-dom/test-utils`](/docs/test-utils.html#act), `TestRenderer.act` prepares a component for assertions. Use this version of `act()` to wrap calls to `TestRenderer.create` and `testRenderer.update`.
115+
116+
```javascript
117+
import {create, act} from 'react-test-renderer';
118+
import App from './app.js'; // The component being tested
119+
120+
// render the component
121+
let root;
122+
act(() => {
123+
root = create(<App value={1}/>)
124+
});
125+
126+
// make assertions on root
127+
expect(root.toJSON()).toMatchSnapshot();
128+
129+
// update with some different props
130+
act(() => {
131+
root = root.update(<App value={2}/>);
132+
})
133+
134+
// make assertions on root
135+
expect(root.toJSON()).toMatchSnapshot();
136+
```
137+
107138
### `testRenderer.toJSON()` {#testrenderertojson}
108139

109140
```javascript
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
id: testing-environments
3+
title: Testing Environments
4+
permalink: docs/testing-environments.html
5+
prev: testing-recipes.html
6+
---
7+
8+
<!-- This document is intended for folks who are comfortable with JavaScript, and have probably written tests with it. It acts as a reference for the differences in testing environments for React components, and how those differences affect the tests that they write. This document also assumes a slant towards web-based react-dom components, but has notes for other renderers. -->
9+
10+
This document goes through the factors that can affect your environment and recommendations for some scenarios.
11+
12+
### Test runners {#test-runners}
13+
14+
Test runners like [Jest](https://jestjs.io/), [mocha](https://mochajs.org/), [ava](https://github.com/avajs/ava) let you write test suites as regular JavaScript, and run them as part of your development process. Additionally, test suites are run as part of continuous integration.
15+
16+
- Jest is widely compatible with React projects, supporting features like mocked [modules](#mocking-modules) and [timers](#mocking-timers), and [`jsdom`](#mocking-a-rendering-surface) support. **If you use Create React App, [Jest is already included out of the box](https://facebook.github.io/create-react-app/docs/running-tests) with useful defaults.**
17+
- Libraries like [mocha](https://mochajs.org/#running-mocha-in-the-browser) work well in real browser environments, and could help for tests that explicitly need it.
18+
- End-to-end tests are used for testing longer flows across multiple pages, and require a [different setup](#end-to-end-tests-aka-e2e-tests).
19+
20+
### Mocking a rendering surface {#mocking-a-rendering-surface}
21+
22+
Tests often run in an environment without access to a real rendering surface like a browser. For these environments, we recommend simulating a browser with [`jsdom`](https://github.com/jsdom/jsdom), a lightweight browser implementation that runs inside Node.js.
23+
24+
In most cases, jsdom behaves like a regular browser would, but doesn't have features like [layout and navigation](https://github.com/jsdom/jsdom#unimplemented-parts-of-the-web-platform). This is still useful for most web-based component tests, since it runs quicker than having to start up a browser for each test. It also runs in the same process as your tests, so you can write code to examine and assert on the rendered DOM.
25+
26+
Just like in a real browser, jsdom lets us model user interactions; tests can dispatch events on DOM nodes, and then observe and assert on the side effects of these actions [<small>(example)</small>](/docs/testing-recipes.html#events).
27+
28+
A large portion of UI tests can be written with the above setup: using Jest as a test runner, rendered to jsdom, with user interactions specified as sequences of browser events, powered by the `act()` helper [<small>(example)</small>](/docs/testing-recipes.html). For example, a lot of React's own tests are written with this combination.
29+
30+
If you're writing a library that tests mostly browser-specific behavior, and requires native browser behavior like layout or real inputs, you could use a framework like [mocha.](https://mochajs.org/)
31+
32+
In an environment where you _can't_ simulate a DOM (e.g. testing React Native components on Node.js), you could use [event simulation helpers](https://reactjs.org/docs/test-utils.html#simulate) to simulate interactions with elements. Alternately, you could use the `fireEvent` helper from [`@testing-library/react-native`](https://testing-library.com/docs/native-testing-library).
33+
34+
Frameworks like [Cypress](https://www.cypress.io/), [puppeteer](https://github.com/GoogleChrome/puppeteer) and [webdriver](https://www.seleniumhq.org/projects/webdriver/) are useful for running [end-to-end tests](#end-to-end-tests-aka-e2e-tests).
35+
36+
### Mocking functions {#mocking-functions}
37+
38+
When writing tests, we'd like to mock out the parts of our code that don't have equivalents inside our testing environment (e.g. checking `navigator.onLine` status inside Node.js). Tests could also spy on some functions, and observe how other parts of the test interact with them. It is then useful to be able to selectively mock these functions with test-friendly versions.
39+
40+
This is especially useful for data fetching. It is usually preferable to use "fake" data for tests to avoid the slowness and flakiness due to fetching from real API endpoints [<small>(example)</small>](/docs/testing-recipes.html#data-fetching). This helps make the tests predictable. Libraries like [Jest](https://jestjs.io/) and [sinon](https://sinonjs.org/), among others, support mocked functions. For end-to-end tests, mocking network can be more difficult, but you might also want to test the real API endpoints in them anyway.
41+
42+
### Mocking modules {#mocking-modules}
43+
44+
Some components have dependencies for modules that may not work well in test environments, or aren't essential to our tests. It can be useful to selectively mock these modules out with suitable replacements [<small>(example)</small>](/docs/testing-recipes.html#mocking-modules).
45+
46+
On Node.js, runners like Jest [support mocking modules](https://jestjs.io/docs/en/manual-mocks). You could also use libraries like [`mock-require`](https://www.npmjs.com/package/mock-require).
47+
48+
### Mocking timers {#mocking-timers}
49+
50+
Components might be using time-based functions like `setTimeout`, `setInterval`, or `Date.now`. In testing environments, it can be helpful to mock these functions out with replacements that let you manually "advance" time. This is great for making sure your tests run fast! Tests that are dependent on timers would still resolve in order, but quicker [<small>(example)</small>](/docs/testing-recipes.html#timers). Most frameworks, including [Jest](https://jestjs.io/docs/en/timer-mocks), [sinon](https://sinonjs.org/releases/v7.3.2/fake-timers/) and [lolex](https://github.com/sinonjs/lolex), let you mock timers in your tests.
51+
52+
Sometimes, you may not want to mock timers. For example, maybe you're testing an animation, or interacting with an endpoint that's sensitive to timing (like an API rate limiter). Libraries with timer mocks let you enable and disable them on a per test/suite basis, so you can explicitly choose how these tests would run.
53+
54+
### End-to-end tests {#end-to-end-tests-aka-e2e-tests}
55+
56+
End-to-end tests are useful for testing longer workflows, especially when they're critical to your business (such as payments or signups). For these tests, you'd probably want to test both how a real browser renders the whole app, fetches data from the real API endpoints, uses sessions and cookies, navigates between different links. You might also likely want to make assertions not just on the DOM state, but on the backing data as well (e.g. to verify whether the updates have been persisted to the database).
57+
58+
In this scenario, you would use a framework like [Cypress](https://www.cypress.io/) or a library like [puppeteer](https://github.com/GoogleChrome/puppeteer) so you can navigate between multiple routes and assert on side effects not just in the browser, but potentially on the backend as well.

0 commit comments

Comments
 (0)