Often we need to test a piece of code that make requests to a third-party service. In that case, we don’t want to rely on a third-party service being online to run our tests. Even if the third-party service is online, we still don’t want to depend on it because our internet connection may be slow or the service may be not fast enough for testing purposes. Also, we always want our tests to run as fast as possible, so we don’t discourage our developers to run the tests constantly. For all those purposes, we have a perfect tool: mocking.
Image that we have an endpoint on our application that fetches Star Wars characters like this:
app.get('/characters/:id', async (req, res) => {
const { id } = req.params
const result = await axios.get(`https://swapi.dev/api/people/${id}`)
res.send(result.data)
})
And, the respective test like this:
it('should fetch character', async () => {
const response = await request(app.express)
.get('/characters/1')
.expect(200)
expect(response.body).toMatchObject({
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male'
})
})
So far so good. But, let’s pretend that we got no internet, let’s try running our tests:
$ npx jest
FAIL test/app.test.js
✓ should say hello world (19 ms)
✓ should create pet (23 ms)
✕ should fetch character (20 ms)
● should fetch character
expected 200 "OK", got 500 "Internal Server Error"
22 | const response = await request(app.express)
23 | .get('/characters/1')
> 24 | .expect(200)
| ^
25 |
26 | expect(response.body).toMatchObject({
27 | name: 'Luke Skywalker',
at Object.<anonymous> (test/app.test.js:24:6)
...
As expected, we were unable to run our tests. Luckily, we can get around this.
The axios-mock-adapter helps us mock responses. Mocking is replicating a
specific behavior. So, by mocking the response, we immitating the third-party service
behavior. Let’s see how it looks like making a request using axios-mock-adapter.
it('should fetch character', async () => {
const mock = new MockAdapter(axios)
mock.onGet('https://swapi.dev/api/people/1').reply(200, {
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male'
})
const response = await request(app.express)
.get('/characters/1')
.expect(200)
expect(response.body).toMatchObject({
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male'
})
})
And, if we try to run our tests again, we should see all of them succeed, even if we have no internet or the service is unavailable:
$ npx jest
PASS test/app.test.js
✓ should say hello world (10 ms)
✓ should create pet (13 ms)
✓ should fetch character (3 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 0.338 s, estimated 1 s
Ran all test suites.
Continue reading: Node.js testing - Mocking