-
Notifications
You must be signed in to change notification settings - Fork 2
Testing
The back end uses Jest as the testing framework of choice and nock to mock requests.
The front end uses Jest as the testing framework of choice and React Testing Library for APIs for working with React components in tests.
Unit tests
Integration tests
- We try to mostly write integration tests, with unit tests when necessary
- On the front-end, in addition to normal integration tests, we also have a type of integration test called snapshot tests. Read more here. To update snapshot tests that fail due to an expected added feature or update, simply execute
npm test -- -u
End to end tests
Make sure you are in the correct working directory.
$ pwd
~/waterthetrees/wtt_server
Then run the command:
npm test
You can add additional arguments to npm test
by suffixing it with --
, followed by additional command line arguments.
For all configuration options read Jest CLI Options.
Run tests that match a pattern or file name.
npm test -- myTest.test.js
A test consists of three functional sections.
-
Arrange – Set up input variables and preconditions.
-
Act – Perform the behavior under test with the arranged parameters. (typically 1 line of code)
-
Assert – Verify the result. (typically 1 line of code)
Test the outcomes of triggering an action (e.g. API call). That is, we care about what happens at the end of the action, not how it happens.
Some aspects to check for are:
-
Response - Check the response data correctness, schema, and HTTP status.
-
A new state - If the behavior under test modifies some data, check that the data is updated correctly.
-
Observability - Some things must be monitored, like errors or remarkable business events. When a transaction fails, not only do we expect the right response but also correct error handling and proper logging/metrics.
In happy path testing, we test the functionality in the way that it was designed to work. Don't try to break it. If all the correct actions were taken, what should the response be?
Only after we test the happy path should we test for corner cases.
Group tests by routes and within each route use the When... Then... naming pattern to tell the expected behavior of each path. Name all tests clearly enough so that a newcomer could understand the intended outcomes of an action solely through reading the test's description.
Each test should work in isolation and not depend on, nor be affected by previous tests.
If you set up a nock object
nock('http:https://localhost:3002/api/trees').get('9').reply(200);
And you get Nock: No match for request
after running the test
Nock: No match for request {
"method": "GET",
"url": "http:https://localhost:3002/api/trees/9/",
"headers": {
"accept": "application/json, text/plain, */*",
"user-agent": "axios/0.21.1"
}
}
You must have a matching request to the URL specified in the nock object.
const res = await axios.get('http:https://localhost:3002/api/trees/9');
Now we should have a matching call, but the error persists. Double check that both requests resolve to the same URL. For this example, we must change the argument in .get()
from the nock object.
❌ nock('http:https://localhost:3002/api/trees').get('9').reply(200)
✅ nock('http:https://localhost:3002/api/trees').get('/9').reply(200);
Although address that axios is called on should contain the port that the server is on, the nock object should be called without the port.
const response = await axios.get('/api/trees/9');
nock('http:https://localhost/api').get('/tree/9');
A nock object only be used once by default.
nock('http:https://localhost:3002/api/trees').get('/9').reply(200);
const res1 = await axios.get('http:https://localhost:3002/api/trees/9');
const res2 = await axios.get('http:https://localhost:3002/api/trees/9');
Although res1
and res2
have the same exact API call, the response from res1
will match the reply block in the nock object while the response from res2
while correspond to a non-mocked API call.
To use the same nock object for multiple API calls, consider using .persist().