Skip to content

Commit 88326b5

Browse files
committed
Update testing.md
1 parent 5368538 commit 88326b5

File tree

1 file changed

+38
-43
lines changed

1 file changed

+38
-43
lines changed

developer_docs/testing.md

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
# Testing
2-
For an initial basic overview of testing for React apps, [you can read what the React developers have to say about it](https://reactjs.org/docs/testing.html).
2+
For an initial basic overview of testing for React apps, [you can read what the React developers have to say about it](https://reactjs.org/docs/testing.html). We use both unit tests and integration tests.
33

44
We are testing React components by rendering the component trees in a simplified test environment and making assertions on what gets rendered and what functions get called.
55

6-
Many files still don't have tests, so if you're looking to get started as a contributor, this would be a great place to start!
6+
Many files still don't have tests, so **if you're looking to get started as a contributor, this would be a great place to start!**
77

88
## What's in this document
99
- [Testing dependencies](#testing-dependencies)
1010
- [Useful testing commands](#Useful-testing-commands)
11+
- [Our testing methods](#Our-testing-methods)
1112
- [Why write tests](#Why-write-tests)
1213
- [When to run tests](#When-to-run-tests)
1314
- [Writing a test](#Writing-a-test)
1415
- [Files to be aware of](#Files-to-be-aware-of)
1516
- [Testing plain components](#Testing-plain-components)
1617
- [Testing Redux](#Testing-Redux)
1718
- [How to handle API calls in tests](#How-to-handle-API-calls-in-tests)
18-
- [Some more background on tests](#Some-more-background-on-tests)
1919
- [Internationalization](#internationalization)
20+
- [Useful terminology to know](#Useful-terminology-to-know)
2021
- [Tips](#Tips)
2122
- [More resources](#More-resources)
2223
- [References](#References)
@@ -55,46 +56,56 @@ $ npm run test -- Sketchlist.test.js -u
5556

5657
Find more commands in the [Jest documentation](https://jestjs.io/docs/cli).
5758

59+
## Our testing methods
60+
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:
63+
1. User facing (like a text input field or a user form component)
64+
2. Used across multiple components like a reusable dropdown menu or reusable table element
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.
67+
68+
### Integration tests
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.
70+
71+
See [this great article on CSS tricks](https://css-tricks.com/react-integration-testing-greater-coverage-fewer-tests/) about integration tests for more information about this.
72+
73+
To reiterate, we use integration tests to test our "happy path" flows and maximize coverage on individual components that are only used once. We use unit tests to test the robustness of user-facing components and reusable components.
74+
75+
### Snapshot testing
76+
You can save a snapshot of what the HTML looks like when the component is rendered.
77+
5878
## Why write tests
59-
- Good place to start if you're learning the codebase because it's harder to mess up production code
60-
- Benefits all future contributors by allowing them to check their changes for errors
61-
- Increased usage: Most code with only ever have a single invocation point, but this means that code might not be particularly robust and lead to bugs if a different devleoper reuses it in a different context. Writing tests increases the usage of the code in question and may improve the long-term durability, along with leading developers to refactor their code to be more usable. [[3]](#References)
62-
- Lets you check your own work and feel more comfortable sumbitting PRs
63-
- Catches easy-to-miss errors
64-
- Good practice for large projects
79+
- Good place to start if you're learning the codebase.
80+
- Benefits all future contributors by allowing them to check their changes for errors.
81+
- Increased usage: Most code with only ever have a single invocation point, but this means that code might not be particularly robust and lead to bugs if a different developer reuses it in a different context. Writing tests increases the usage of the code in question and may improve the long-term durability, along with leading developers to refactor their code to be more usable. [[3]](#References)
82+
- Lets you check your own work and feel more comfortable sumbitting PRs.
83+
- Catches easy-to-miss errors.
84+
- Good practice for large projects.
6585
- Many of the existing components don't have tests yet, and you could write one :-)
6686

6787
## When to run tests
6888

69-
When you make a git commit, the tests will be run automatically for you (maybe? check with Cassie again). Tests will also be run when you make a PR and if you fail any tests it blocks the merge.
89+
When you ``git push`` your code, the tests will be run automatically for you. Tests will also be run when you make a PR and if you fail any tests it blocks the merge.
7090

7191
When you modify an existing component, it's a good idea to run the test suite to make sure it didn't make any changes that break the rest of the application. If they did break some tests, you would either have to fix a bug component or update the tests to match the new expected functionality.
7292

7393
## Writing a test
7494
Want to get started writing a test for a new file or an existing file, but not sure how?
7595

76-
7796
### For React components
7897
1. Make a new file directly adjacent to your file. For example, if ``example.jsx`` is ``src/components/example.jsx``, then you would make a file called ``example.test.jsx`` at ``src/components/example.test.jsx``
7998
2. Check if the component is connected to redux or not.
8099
3. If it is, see the [redux section](#Testing-Redux) below on how to write tests for that.
81100
4. If it's not, see the [section below on writing tests for unconnected components](#Testing-plain-components).
82101
)
83-
5. "Arange, Act, Assert:" In other words, *arrange* the set up for the test, *act* out whatever the subject's supposed to do, and *assert* on the results. [[3]](#References)
84-
85-
### In every test file
86-
Maybe we want to add these as comments??
87-
- What behavior is and isn't covered by the suites What dependencies should be replaced with mocks and what should be left realistic
88-
- The primary design benefit (if any) of these tests
89-
- The primary regression protection (if any) provided by these tests
90-
- What an example test should look like
91-
- The maximum permissible elapsed time for a run of an individual test or for the full suit
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)
92103

93104
### Consistency across tests
94105
> "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."
95106
- We want to default to using meaningless test data stored in the redux-test-stores folder.
96107
- Be sure to follow the folder structure
97-
- Follow the rendering guidelines set up for the components in this README.
108+
- Follow the rendering guidelines set up for the components in this ["Writing a Test"](#Writing-a-test) section.
98109

99110
### Querying for elements
100111
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.
@@ -103,10 +114,11 @@ Read about the recommended order of priority for queries in [the testing library
103114
### What to test
104115
For any type of component, you might want to consider testing:
105116
- 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.
106-
- a previously saved snapshot of the HTML matches a snapshot taken during testing.
107-
- what else?? help!
117+
- 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+
- 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+
- more details on testing behavior in the component-specific sections
108120

109-
>Only test the behaviors you know you need to care about. For example, if the desired behavior of a particular edge case doesn't truly matter yet or isn't fully understood, don't write a test for it yet. Doing so would restrict the freedom to refactor the implementation. Additionally, it will send the signal to future readers that this behavior is actually critical, when it very well might not be (perhaps a form of [accidental creativity]()). [[3]](#References)
121+
>Only test the behaviors you know you need to care about. For example, if the desired behavior of a particular edge case doesn't truly matter yet or isn't fully understood, don't write a test for it yet. Doing so would restrict the freedom to refactor the implementation. Additionally, it will send the signal to future readers that this behavior is actually critical, when it very well might not be. [[3]](#References)
110122
111123
**Don't test unreachable edge cases:** You would have to add code to your original implementation to guard against these cases. The future proofing and the added cost to the codebase "is generally not worth their preceived potential benefits" [[3]](#References)
112124

@@ -242,10 +254,6 @@ function reduxRender(
242254
### redux_test_stores
243255
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.
244256
245-
### jest configs in package.json
246-
247-
in progress
248-
249257
## Testing plain components
250258
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:
251259
@@ -319,7 +327,6 @@ Consider what you want to test. Some possible things might be:
319327
expect(yourMockFunction).toHaveBeenCalledTimes(1);
320328
expect(yourMockFunction.mock.calls[0][0]).toBe(argument);
321329
```
322-
- what else???? help!
323330
324331
## Testing Redux
325332
@@ -427,21 +434,8 @@ The benefit of this is that you can control exactly what happens when any axios
427434
428435
A few components also import ``./client/i18n.js`` (or ``./client/utils/formatDate``, which imports the first file), in which the ``i18n.use(Backend)`` line can sometimes throw a sneaky ERRCONNECTED error. You can resolve this by mocking that file as described in [this section](#Troubleshooting).
429436
430-
## Some more background on tests
431-
432-
### Test Driven Development (TDD)
433-
Do we want a section here about TDD history?
434-
435-
### snapshot testing
436-
You can save a snapshot of what the HTML looks like when the component is rendered.
437-
438-
### integration tests
439-
Testing multiple components together. A small example is rendering a parent component in order to test the interactions between children components. For frontend development, integration tests might focus on end-to-end flows using Puppeter or another type of headless browser testing. We don't do this just yet.
440-
441-
### unit tests
442-
Most of our tests are of this type. In this, 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.
443437
444-
### Other terminology for mocking
438+
## Useful terminology to know
445439
Thanks [Test Double Wiki](https://github.com/testdouble/contributing-tests/wiki/Test-Double) for the definitions.
446440
#### Test double
447441
Broadest available term to describe any fake thing used in place of a real thing for a test.
@@ -465,6 +459,7 @@ This project uses i18next for internationalization. If you import the render fun
465459
1. Make test fail at least once to make sure it was a meaningful test
466460
2. "If you or another developer change the component in a way that it changes its behaviour at least one test should fail." - [How to Unit Test in React](https://itnext.io/how-to-unit-test-in-react-72e911e2b8d)
467461
3. Avoid using numbers or data that seem "special" in your tests. For example, if you were checking the "age" variable in a component is a integer, but checked it as so ``expect(person.ageValidator(18)).toBe(true)``, the reader might assume that the number 18 had some significance to the function because it's a significant age. It would be better to have used 1234.
462+
4. Tests should help other developers understand the expected behavior of the component that it's testing
468463
469464
## More Resources
470465
- [React Testing Library Cheatsheet](https://testing-library.com/docs/react-testing-library/cheatsheet/)

0 commit comments

Comments
 (0)