I am using JEST framework for unit testing for my node.js project. I Used mockImplementationOnce for mocking thirdParty library methods as follows: jest.mock('abc', () => { return { a: { b: jest.fn() } }; }); const abcjs= require('abc');
describe("1st test", () => {
test("should return true", async () => {
abcjs.a.b.mockImplementationOnce(() => Promise.resolve(
return true}
));
});
});
describe("2nd test", () => {
test("should return false", async () => {
abcjs.a.b.mockImplementationOnce(() => Promise.resolve(
return false}
));
});
});
1st test executed successfully , but 2nd test Its calling the actual method, its not mocking. I tried resetting mocks afterEach but it didn't help.
I was having the same issue yesterday with mocking aws-sdk.
It turned out that after you have mocked a whole module once, you can't override the behaviour of that mock in the same file again.
I am surprised that your first test actually passed, even though your default mock function was simply a jest.fn() without any return value.
There is a whole discussion here on this - https://github.com/facebook/jest/issues/2582
Final Solution from the thread:
// no mocking of the whole module
const abcjs= require('abc');
describe("1st test", () => {
test("should return true", async () => {
// Try using jest.spyOn() instead of jest.fn
jest.spyOn(abcjs.a,'b').mockImplementationOnce(() => Promise.resolve(true)));
//expect statement here
});
});
describe("2nd test", () => {
jest.restoreAllMocks(); // <----------- remember to add this
test("should return false", async () => {
jest.spyOn(abcjs.a,'b').mockImplementationOnce(() => Promise.resolve(false)));
// expect statement here
});
});
Basically, DON'T mock the whole module but instead only mock the functions you want from it.
Maybe this can be a reference for you. If it's me, then the idea looks like this:
Think of it as the third party library method you are referring to.
/**
* Module dependencies.
*/
const abcjs = {
a: { b: () => null }
}
then the test scenario that I imagine is ...
describe('a test scenario', () => {
afterEach(() => {
// Restores all mocks back to their original value.
// only works when the mock was created with jest.spyOn;
jest.restoreAllMocks()
})
describe('1st test', () => {
test('should return true', async () => {
jest.spyOn(abcjs.a, 'b').mockImplementation()
/**
* Accepts a value that will be returned for one call to the mock function. Can be chained so that
* successive calls to the mock function return different values. When there are no more
* `mockResolvedValueOnce` values to use, calls will return a value specified by `mockResolvedValueOnce`.
*/
abcjs.a.b.mockResolvedValueOnce(true).mockResolvedValueOnce('isTrue')
let resultExpected = await abcjs.a.b()
// Ensures that a mock function is called an exact number of times.
expect(abcjs.a.b).toHaveBeenCalledTimes(1)
// Used when you want to check that two objects have the same value.
expect(resultExpected).toEqual(true)
// try to invoked the function for second times...
resultExpected = await abcjs.a.b()
// Ensures that a mock function is called an exact number of times...
// which is the second time !
expect(abcjs.a.b).toHaveBeenCalledTimes(2)
// Used when you want to check that two objects have the same value.
expect(resultExpected).toEqual('isTrue')
})
})
describe('2nd test', () => {
test('should return false', async () => {
jest.spyOn(abcjs.a, 'b').mockImplementation()
abcjs.a.b.mockResolvedValueOnce(false)
const resultExpected = await abcjs.a.b()
expect(abcjs.a.b).toHaveBeenCalledTimes(1)
expect(resultExpected).toEqual(false)
})
})
})
If it was me, I prefer to return the promise using this
mockFn.mockResolvedValue(value)
or mockFn.mockRejectedValue(value)
see the doc instead of mockImplementation(() => Promise.resolve(value))
This is just one approach to testing that I can describe. Hopefully this will give you an idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With