In the last part of this series, we were introduced to the concept of mocking. It turns out that we can also mock javascript functions as we are going to see. Let’s say that we have function A that happens to call function B but we don’t want to actually call function B while testing A. How can we get around this? Mocking is the answer! Let’s say we have the following situation:
src/getGreet.js:
const getPlanet = require('./getPlanet')
module.exports = function getGreet () {
const planet = getPlanet()
return `Hello from ${planet}!`
}
src/getPlant.js:
module.exports = function getPlanet () {
return 'earth'
}
tests/getGreet.test.js:
const getPlanet = require('../src/getPlanet')
it('should say "Hello from jupyter!"', () => {
expect(getGreet()).toBe('Hello from jupyter!')
})
As you would expect, if we run the tests, we are going to see a test failing:
$ npx jest test/getGreet.test.js
FAIL test/getGreet.test.js
✕ should say "Hello from jupyter!" (3 ms)
● should say "Hello from jupyter!"
expect(received).toBe(expected) // Object.is equality
Expected: "Hello from jupyter!"
Received: "Hello from earth!"
2 |
3 | it('should say "Hello from jupyter!"', () => {
> 4 | expect(a()).toBe('Hello from jupyter!')
| ^
5 | })
6 |
at Object.<anonymous> (test/getGreet.test.js:4:15)
To fix this, we are going to use a jest method called mock, like this:
const getGreet = require('../src/getGreet')
const getPlanet = require('../src/getPlanet')
jest.mock('../src/getPlanet')
it('should say "Hello from jupyter!"', () => {
getPlanet.mockReturnValue('jupyter')
expect(a()).toBe('Hello from jupyter!')
})
Let’s break down what’s going on. First, we import getPlanet, so we can interact with it.
Then, we call jest.mock and pass getPlanet path as parameter. This will intercept all requires
to getPlanet and return a jest mock instance instead. This mock instance has special methods
we can call, like mockReturnValue. And finally, getPlanet.mockReturnValue makes every call to
getPlanet return jupyter.
Another useful thing we can do with mocks is assert if they have been called. Let’s assume the following scenario:
src/caller.js:
const callee = require('./callee')
module.exports = function caller () {
callee()
return 'function callee have been called'
}
But, how can we make sure that function callee have been called? Mocks can help us with that too!
test/caller.test.js:
const caller = require('../src/caller')
const callee = require('../src/callee')
jest.mock('../src/callee')
it('should call callee', () => {
caller()
expect(callee).toHaveBeenCalled()
})
As you expect, toHaveBeenCalled verifies if the mock callee have been called. If we run the tests, we should see all tests passing:
$ npx jest test/caller.test.js
PASS test/caller.test.js
✓ should call callee (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.132 s
Another useful verification function is toHaveBeenCalledWith(arg1, arg2, ...) which checks if the function
has been called with given arguments.
You can see all the verification functions jest have here.