-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Document testing * Update README.md * Update README.md * Clarify our recommendations on testing * Okay, that was too much. :-) * Add a few more things
- Loading branch information
Showing
2 changed files
with
225 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ You can find the most recent version of this guide [here](https://github.com/fac | |
- [Folder Structure](#folder-structure) | ||
- [Available Scripts](#available-scripts) | ||
- [npm start](#npm-start) | ||
- [npm test](#npm-test) | ||
- [npm run build](#npm-run-build) | ||
- [npm run eject](#npm-run-eject) | ||
- [Displaying Lint Output in the Editor](#displaying-lint-output-in-the-editor) | ||
|
@@ -24,6 +25,17 @@ You can find the most recent version of this guide [here](https://github.com/fac | |
- [Integrating with a Node Backend](#integrating-with-a-node-backend) | ||
- [Proxying API Requests in Development](#proxying-api-requests-in-development) | ||
- [Adding `<meta>` Tags](#adding-meta-tags) | ||
- [Running Tests](#running-tests) | ||
- [Filename Conventions](#filename-conventions) | ||
- [Command Line Interface](#command-line-interface) | ||
- [Version Control Integration](#version-control-integration) | ||
- [Writing Tests](#writing-tests) | ||
- [Testing Components](#testing-components) | ||
- [Using Third Party Assertion Libraries](#using-third-party-assertion-libraries) | ||
- [Coverage Reporting](#coverage-reporting) | ||
- [Continuous Integration](#continuous-integration) | ||
- [Disabling jsdom](#disabling-jsdom) | ||
- [Experimental Snapshot Testing](#experimental-snapshot-testing) | ||
- [Deployment](#deployment) | ||
- [Now](#now) | ||
- [Heroku](#heroku) | ||
|
@@ -97,6 +109,11 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser. | |
The page will reload if you make edits.<br> | ||
You will also see any lint errors in the console. | ||
|
||
### `npm test` | ||
|
||
Launches the test runner in the interactive watch mode. | ||
See the section about [running tests](#running-tests) for more information. | ||
|
||
### `npm run build` | ||
|
||
Builds the app for production to the `build` folder.<br> | ||
|
@@ -425,15 +442,15 @@ render() { | |
The above form is looking for a variable called `REACT_APP_SECRET_CODE` from the environment. In order to consume this | ||
value, we need to have it defined in the environment: | ||
### Windows (cmd.exe) | ||
#### Windows (cmd.exe) | ||
```cmd | ||
set REACT_APP_SECRET_CODE=abcdef&&npm start | ||
``` | ||
(Note: the lack of whitespace is intentional.) | ||
### Linux, OS X (Bash) | ||
#### Linux, OS X (Bash) | ||
```bash | ||
REACT_APP_SECRET_CODE=abcdef npm start | ||
|
@@ -522,6 +539,201 @@ Then, on the server, regardless of the backend you use, you can read `index.html | |
If you use a Node server, you can even share the route matching logic between the client and the server. However duplicating it also works fine in simple cases. | ||
## Running Tests | ||
>Note: this feature is available with `[email protected]` and higher. | ||
>[Read the migration guide to learn how to enable it in older projects!](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md#migrating-from-023-to-030) | ||
Create React App uses [Jest](https://facebook.github.io/jest/) as its test runner. To prepare for this integration, we did a [major revamp](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html) of Jest so if you heard bad things about it, give it another try. | ||
Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness. | ||
While Jest provides browser globals such as `window` thanks to [jsdom](https://github.com/tmpvar/jsdom), they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks. | ||
We recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App. | ||
### Filename Conventions | ||
Jest will look for test files with any of the following popular naming conventions: | ||
* Files with `.js` suffix in `__tests__` folders. | ||
* Files with `.test.js` suffix. | ||
* Files with `.spec.js` suffix. | ||
The `.test.js` / `.spec.js` files (or the `__tests__` folders) can be located at any depth under the `src` top level folder. | ||
We recommend to put the test files (or `__tests__` folders) next to the code they are testing so that relative imports appear shorter. For example, if `App.test.js` and `App.js` are in the same folder, the test just needs to `import App from './App'` instead of a long relative path. | ||
### Command Line Interface | ||
When you run `npm test`, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like `npm start` recompiles the code. | ||
The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you could keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run: | ||
![Jest watch mode](http://facebook.github.io/jest/img/blog/15-watch.gif) | ||
### Version Control Integration | ||
By default, when you run `npm test`, Jest will only run the tests related to files changed since last commit. This is an optimization designed to make your tests runs fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests. | ||
Jest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press `a` in the watch mode to force Jest to run all tests. | ||
Jest will always run all tests on a [continuous integration](#continuous-integration) server or if the project is not inside a Git or Mercurial repository. | ||
### Writing Tests | ||
To create tests, add `it()` blocks with the name of the test and its code. You may optionally wrap them in `describe()` blocks for logical grouping but this is neither required nor recommended. | ||
Jest provides a built-in `expect()` global function for making assertions. A basic test could look like this: | ||
```js | ||
import sum from './sum'; | ||
it('sums numbers', () => { | ||
expect(sum(1, 2)).toEqual(3); | ||
expect(sum(2, 2)).toEqual(4); | ||
}); | ||
``` | ||
All `expect()` matchers supported by Jest are [extensively documented here](http://facebook.github.io/jest/docs/api.html#expect-value). | ||
You can also use [`jest.fn()` and `expect(fn).toBeCalled()`](http://facebook.github.io/jest/docs/api.html#tobecalled) to create “spies” or mock functions. | ||
### Testing Components | ||
There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes. | ||
Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating simple smoke tests for your components: | ||
```js | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import App from './App'; | ||
it('renders without crashing', () => { | ||
const div = document.createElement('div'); | ||
ReactDOM.render(<App />, div); | ||
}); | ||
``` | ||
This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot value with very little effort so they are great as a starting point, and this is the test you will find in `src/App.test.js`. | ||
When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior. | ||
If you’d like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). You can write a smoke test with it too: | ||
```sh | ||
npm install --save-dev enzyme react-addons-test-utils | ||
``` | ||
```js | ||
import React from 'react'; | ||
import { shallow } from 'enzyme'; | ||
import App from './App'; | ||
it('renders without crashing', () => { | ||
shallow(<App />); | ||
}); | ||
``` | ||
Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `<App>` and doesn’t go deeper. For example, even if `<App>` itself renders a `<Button>` that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports [full rendering with `mount()`](http://airbnb.io/enzyme/docs/api/mount.html), and you can also use it for testing state changes and component lifecyle. | ||
You can read the [Enzyme documentation](http://airbnb.io/enzyme/) for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you don’t have to use them because Jest provides built-in `expect()` and `jest.fn()` for spies. | ||
Here is an example from Enzyme documentation that asserts specific output, rewritten to use Jest matchers: | ||
```js | ||
import React from 'react'; | ||
import { shallow } from 'enzyme'; | ||
import App from './App'; | ||
it('renders welcome message', () => { | ||
const wrapper = shallow(<App />); | ||
const welcome = <h2>Welcome to React</h2>; | ||
// expect(wrapper.contains(welcome)).to.equal(true); | ||
expect(wrapper.contains(welcome)).toEqual(true); | ||
}); | ||
``` | ||
All Jest matchers are [extensively documented here](http://facebook.github.io/jest/docs/api.html#expect-value). | ||
Nevertheless you can use a third-party assertion library like Chai if you want to, as described below. | ||
### Using Third Party Assertion Libraries | ||
We recommend that you use `expect()` for assertions and `jest.fn()` for spies. If you are having issues with them please [file those against Jest](https://github.com/facebook/jest/issues/new), and we’ll fix them. We intend to keep making them better for React, supporting, for example, [pretty-printing React elements as JSX](https://github.com/facebook/jest/pull/1566). | ||
However, if you are used to other libraries, such as [Chai](http://chaijs.com/) and [Sinon](http://sinonjs.org/), or if you have existing code using them that you’d like to port over, you can import them normally like this: | ||
```js | ||
import sinon from 'sinon'; | ||
import { expect } from 'chai'; | ||
``` | ||
and then use them in your tests like you normally do. | ||
### Coverage Reporting | ||
Jest has an integrated coverage reporter that works well with ES6 and requires no configuration. | ||
Run `npm test -- --coverage` (note extra `--` in the middle) to include a coverage report like this: | ||
![coverage report](http://i.imgur.com/5bFhnTS.png) | ||
Note that tests run much slower with coverage so it is recommended to run it separately from your normal workflow. | ||
### Continuous Integration | ||
By default `npm test` runs the watcher with interactive CLI. However, you can force it to run tests once and finish the process by setting an environment variable called `CI`. Popular CI servers already set it by default but you can do this yourself too: | ||
#### Windows (cmd.exe) | ||
```cmd | ||
set CI=true&&npm test | ||
``` | ||
(Note: the lack of whitespace is intentional.) | ||
#### Linux, OS X (Bash) | ||
```bash | ||
CI=true npm test | ||
``` | ||
This way Jest will run tests once instead of launching the watcher. | ||
If you find yourself doing this often in development, please [file an issue](https://github.com/facebookincubator/create-react-app/issues/new) to tell us about your use case because we want to make watcher the best experience and are open to changing how it works to accommodate more workflows. | ||
### Disabling jsdom | ||
By default, the `package.json` of the generated project looks like this: | ||
```js | ||
// ... | ||
"scripts": { | ||
// ... | ||
"test": "react-scripts test --env=jsdom" | ||
} | ||
``` | ||
If you know that none of your tests depend on [jsdom](https://github.com/tmpvar/jsdom), you can safely remove `--env=jsdom`, and your tests will run faster. | ||
To help you make up your mind, here is a list of APIs that **need jsdom**: | ||
* Any browser globals like `window` and `document` | ||
* [`ReactDOM.render()`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render) | ||
* [`TestUtils.renderIntoDocument()`](https://facebook.github.io/react/docs/test-utils.html#renderintodocument) ([a shortcut](https://github.com/facebook/react/blob/34761cf9a252964abfaab6faf74d473ad95d1f21/src/test/ReactTestUtils.js#L83-L91) for the above) | ||
* [`mount()`](http://airbnb.io/enzyme/docs/api/mount.html) in [Enzyme](http://airbnb.io/enzyme/index.html) | ||
In contrast, **jsdom is not needed** for the following APIs: | ||
* [`TestUtils.createRenderer()`](https://facebook.github.io/react/docs/test-utils.html#shallow-rendering) (shallow rendering) | ||
* [`shallow()`](http://airbnb.io/enzyme/docs/api/shallow.html) in [Enzyme](http://airbnb.io/enzyme/index.html) | ||
Finally, jsdom is also not needed for [snapshot testing](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html). Longer term, this is the direction we are interested in exploring, but snapshot testing is [not fully baked yet](https://github.com/facebookincubator/create-react-app/issues/372) so we don’t officially encourage its usage yet. | ||
### Experimental Snapshot Testing | ||
Snapshot testing is a new feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. | ||
This feature is experimental and still [has major usage issues](https://github.com/facebookincubator/create-react-app/issues/372) so we only encourage you to use it if you like experimental technology. We intend to gradually improve it over time and eventually offer it as the default solution for testing React components, but this will take time. [Read more about snapshot testing.](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html) | ||
## Deployment | ||
By default, Create React App produces a build assuming your app is hosted at the server root. | ||
|