Problem
Iets say you have the file
// file.js
export function b() {
return 'B'
}
export function a() {
return b()
}
module.exports = {
a,
b,
}
function a is calling function b internally. To mock the function b can be very difficult.
You will probably do something like this in your test
Using jest.mock method
jest.mock('./file', () => {
const original = jest.requireActual('./file')
return {
...orignial,
b: jest.fn()
}
})
const f = require('./file')
test('a', () => {
f.b.mockReturnValue('C')
expect(f.a()).toBe('C')
// this will failed, it got 'B'
})
Using jest.spyOn method
const f = require('./file')
test('a', () => {
jest.spyOn(f, 'b').mockReturnValue('C')
expect(f.a()).toBe('C')
// it sill failed!, it got 'B'
})
This is not a bug, above 2 methods are working fine. The main reason is because the reference point. Once the function is mocked and print it out you will see something like this.
[Function: b] {
_isMockFunction: true,
getMockImplementation: [Function (anonymous)],
mock: [Getter/Setter],
mockClear: [Function (anonymous)],
mockReset: [Function (anonymous)],
mockRestore: [Function (anonymous)],
...
...
}
Now you try print out the function b that called in function a. And, run the test again.
export function a() {
console.log(b) // it will print [Function: b] (without the mock property)
return b()
}
Solution 1
Move function b to another file.
// b.js
export function b() {
return 'B'
}
// file.js
import {b} from "./b"
export function a() {
return b()
}
In this case, just mock b will do. I believe you know better than me.
Solution 2
Using the same reference point. This could be abit ugly to you codebase. I think is fine for me.
// file.js
export function b() {
return 'B'
}
export function a() {
return module.exports.b() // magic here
}
module.exports = {
a,
b,
}
Or you can do something like, if this is the way you define your module.
// file.js
module.exports = {
b: () => {
return 'B'
},
a: () => {
return this.b() // this magic
}
}
Both are achive the same result and same principle.
Top comments (2)
Solution 3 is to use a dependency injection or composition pattern to give you more control over your dependencies 👀
Yeah~ true.