You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: developer_docs/testing.md
+34-20Lines changed: 34 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,11 +59,11 @@ Find more commands in the [Jest documentation](https://jestjs.io/docs/cli).
59
59
## Our testing methods
60
60
61
61
### Unit tests
62
-
In unit tests, you're testing a the functionality of a single component and no more. They provide lots of feedback on the specific component that you're testing, with the cost of high [redundant coverage](https://github.com/testdouble/contributing-tests/wiki/Redundant-Coverage) and more time spent refactoring tests when components get rewritten. **Not every file needs a unit test.** Unit tests are most important for components that are either:
62
+
In unit tests, you're testing the functionality of a single component and no more. They provide lots of feedback on the specific component that you're testing, with the cost of high [redundant coverage](https://github.com/testdouble/contributing-tests/wiki/Redundant-Coverage) and more time spent refactoring tests when components get rewritten. **Not every file needs a unit test.** Unit tests are most important for components that are either:
63
63
1. User facing (like a text input field or a user form component)
64
64
2. Used across multiple components like a reusable dropdown menu or reusable table element
65
65
66
-
In both of these cases, the component being tested is not merely an implementation detail and is being used more extensively, it's important for the unit tests to test the error cases that could occur to ensure that the component is robust. For example, for a user-facing input field that should only take positive numbers, a unit test would want to cover what happens when users enter negative numbers or letters.
66
+
In both of these cases, the component being tested is not merely an implementation detail. Thus, it's important for the unit tests to test the error cases that could occur to ensure that the component is robust. For example, for a user-facing input field that should only take positive numbers, a unit test would want to cover what happens when users enter negative numbers or letters.
67
67
68
68
### Integration tests
69
69
Testing multiple components together. A small example is rendering a parent component in order to test the interactions between children components. Generally, they validate how multiple units of your application work together. Jest, which is what we use, uses jsdom under the hood to emulate common browser APIs with less overhead than automation like a headless browser, and its mocking tools can stub out external API calls. We use integration tests to maximize coverage and to make sure all the pieces play nice together. We want our integration tests to cover the testing of components that don't have unit tests because they're only used in one place and are merely an implementation detail. The integration tests can test the "happy path" flow, while we expect the unit tests to have tested the error cases already.
@@ -98,22 +98,26 @@ Want to get started writing a test for a new file or an existing file, but not s
98
98
2. Check if the component is connected to redux or not.
99
99
3. If it is, see the [redux section](#Testing-Redux) below on how to write tests for that.
100
100
4. If it's not, see the [section below on writing tests for unconnected components](#Testing-plain-components).
101
-
)
101
+
102
102
5. "Arange, Act, Assert:" In other words, *arrange* the setup for the test, *act* out whatever the subject's supposed to do, and *assert* on the results. [[3]](#References)
103
103
104
-
### Consistency across tests
105
-
> "Teams that adopt a rigid and consistent structure to each test tend to more readily understand each test, because every deviation from the norm can be trusted to be meaningful and somehow specific to the nature of the subject."
106
-
- We want to default to using meaningless test data stored in the redux-test-stores folder.
107
-
- Be sure to follow the folder structure
108
-
- Follow the rendering guidelines set up for the components in this ["Writing a Test"](#Writing-a-test) section.
104
+
### For Redux action creators or reducers
105
+
See the [redux section](#Testing-Redux) below :)
106
+
107
+
### For utility files
108
+
You might still want to write tests for non-component or non-redux files, such as modules with utility functions. What gets tested in this case depends a lot on the module itself, but generally, you would import the module and test the functions within it.
109
109
110
110
### Querying for elements
111
111
Read about the recommended order of priority for queries in [the testing library docs](https://testing-library.com/docs/guide-which-query/#priority). We recommend using roles and text, or labels. You can use this [handy extension](https://chrome.google.com/webstore/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano/related) to do this.
112
112
113
113
114
114
### What to test
115
115
For any type of component, you might want to consider testing:
116
-
- The text or divs that you expect to be on the page are actually there. You can use [Queries](https://testing-library.com/docs/queries/about/) for this.
116
+
- The text or divs that you expect to be on the page are actually there. You can use [Queries](https://testing-library.com/docs/queries/about/) for this. Assertions should make use of the toBeInTheDocument() matcher when asserting that an element exists:
expect(screen.queryByText('Does not exist')).not.toBeInTheDocument();
120
+
```
117
121
- If it's an integration test, you could consider testing the "happy path" flow. For example, in a login form, you would test how a user might enter their username and password and then enter that information.
118
122
- Generally, you want to focus your testing on "user input" -> "expected output" instead of making sure the middle steps work as you would expect. This might mean that you don't need to check that the state changes or class-specific methods occur. This is so that if some of the small details in the implementation of the component changes in the future, the tests can remain the same.
119
123
- more details on testing behavior in the component-specific sections
@@ -125,23 +129,27 @@ For any type of component, you might want to consider testing:
125
129
**Make sure your tests are sufficient:** You want to make sure your test actually specifies all the behaviors you want to ensure the code exhibits. For example, testing that ``1+1 > 0`` would be correct, but insufficient. [[3]](#References)
126
130
127
131
### File structure
128
-
Each test should have a top-level ```describe`` block to group related blocks together, with the name of the component under test.
129
-
*example.test.ts*
132
+
Each test should have a top-level ``describe`` block to group related blocks together, with the name of the component under test.
133
+
134
+
*Example.test.ts*
130
135
131
136
```js
132
-
importexamplefrom'./example';
137
+
import Example from './Example';
133
138
134
-
describe('example', () => {
139
+
describe('<Example.jsx/>', () => {
135
140
it('creates a new example', () => {
136
141
//your tests here
137
142
});
138
143
});
139
144
140
145
```
141
146
147
+
### Consistency across tests
148
+
> "Teams that adopt a rigid and consistent structure to each test tend to more readily understand each test, because every deviation from the norm can be trusted to be meaningful and somehow specific to the nature of the subject."
149
+
- We want to default to using meaningless test data stored in the redux-test-stores folder.
150
+
- Be sure to follow the [folder structure](#Folder-structure)
151
+
- Follow the rendering guidelines set up for the components in this [Writing a Test](#Writing-a-test) section.
142
152
143
-
### For Redux action creators or reducers
144
-
See the [redux section](#Testing-Redux) below :)
145
153
146
154
### Troubleshooting
147
155
1. Check if the component makes any API calls. If it's using axios, jest should already be set up to replace the axios library with a mocked version; however, you may want to [mock](https://jestjs.io/docs/mock-function-api#mockfnmockimplementationoncefn) the axios.get() function with your own version so that GET calls "return" whatever data makes sense for that test.
@@ -164,6 +172,9 @@ You can also see it used in the context of a test [in the SketchList.test.jsx fi
164
172
### Folder structure
165
173
All tests are directly adjacent to the files that they are testing, as described in the [React docs](https://reactjs.org/docs/faq-structure.html#grouping-by-file-type). For example, if you're testing ``examplefolder/Sketchlist.test.jsx``, the test would be in ``examplefolder/Sketchlist.test.jsx``. This is so that the tests are as close as possible to the files. This also means that any snapshot files will be stored in the same folder, such as ``examplefolder/__snapshots__/Sketchlist.test.jsx.snap``
166
174
175
+
CASSIE-WHEREDOWEPUTTHEINTEGRATIONTESTS?
176
+
Integration tests can be placed in the ``__tests__`` folder that's at the root of the client folder. They should be called ``ComponentName.test.integration.jsx``
177
+
167
178
Manual mocks are in ``__mocks__`` folders are adjacent to the modules that they're mocking.
168
179
169
180
Note: Even if you mock a user modulein a ``__mocks__`` folder, user modules have to be explictly mocked in the test too, with``Jest.mock("path_to_module")``
@@ -255,8 +266,9 @@ function reduxRender(
255
266
This folder contains the inital redux states that you can provide to the ``reduxRender`` function when testing. For example, if you want to render the SketchList component with a username of ``happydog`` and some sample sketches, ``redux_test_stores\test_store.js`` contains a definition for that state that you can import and provide to the renderer.
256
267
257
268
## Testing plain components
258
-
If it doesn't contain ``connect(mapStateToProps, mapDispatchToProps)(ComponentName)`` or use hooks like ``useSelector``, then your component is not directly using Redux and testing your component will be simpler and might look something like this:
269
+
If it doesn't contain ``connect(mapStateToProps, mapDispatchToProps)(ComponentName)`` or use hooks like ``useSelector``, then your component is not directly using Redux and testing your component will be simpler and might look something like the code below. Notably, we descibe the component being tested as the [subject under test](http://xunitpatterns.com/SUT.html) by creating a function called ``subject`` that renders the component with the subject dependencies (the props) that are defined in the same scope. They're declared with ``let`` so that they can be overwritten in a nested ``describe``block that tests different dependencies. This keeps the subject function consistent between test suites and explicitly declares variables that can affect the outcome of the test.
259
270
271
+
*MyComponent.test.jsx*
260
272
```js
261
273
import React from 'react';
262
274
import { unmountComponentAtNode } from 'react-dom';
0 commit comments