I am writing a Redux action to fulfill a unit test a but am having trouble with the mocked function call inside the test. I believe I have mocked completeRegistration
correctly, by importing the module it is declared in and then mocking the function from the module reference, but Jest says the function doesn't get called despite the console log statement confirming that the verified.data.success
condition is true
.
Any ideas what am I doing wrong? Thanks
auth.js
export const verifyEmail = ({
originalCode,
confirmCode,
token
}) => async dispatch => {
try {
const body = JSON.stringify({
originalCode,
confirmCode,
registering: true
});
const verified = await axios.post("/api/email/verify", body, config);
if (verified.data.success) {
console.log("Success!") // logs "Success!"
completeRegistration(token); // test is to find out if this function gets called
} else {
return { msg: "Code did not match, please try again" };
}
} catch (err) {
dispatch({
type: REGISTER_FAILED
});
}
};
auth.test.js
import * as auth from "../../actions/auth";
const originalCompleteReg = auth.completeRegistration;
describe("verifyEmail action", () => {
let verifyData;
beforeEach(() => {
verifyData = {
originalCode: "1234546",
confirmCode: "1234546",
token: "87618g1u8ojb98k3jb12i3kwdbcjwvbbi92ueg29eubv" // fake data :p
};
auth.completeRegistration = jest.fn(() => auth.completeRegistration);
moxios.install();
});
afterEach(() => {
auth.completeRegistration = originalCompleteReg;
moxios.uninstall();
});
it("calls completeRegistration function if successful", async () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: { success: true }
});
});
const store = mockStore({ payload: {} });
await store.dispatch(auth.verifyEmail(verifyData));
expect(auth.completeRegistration).toBeCalled();
});
});
Output
verifyEmail action › calls completeRegistration function if successful
expect(jest.fn()).toBeCalled()
Expected number of calls: >= 1
Received number of calls: 0
The problem is that you are not mocking the internal value of completeRegistration
used by verifyEmail
within the auth
module, but the exported value.
When you import a module you get an object with references to the module's functions. If you overwrite a value in the required module, your own reference is overwritten, but the implementation keeps the original reference.
So, in your case, if you call auth.completeRegistration
in your test file you will call the mocked version. But when calling auth.verifyEmail
(which internally calls completeRegistration
), the completeRegistration
it references is not your overwritten version.
I think you should not be testing that your completeRegistration
method is being called (after all, that's an implementation detail). Instead, you should check that your method behaves as expected (i.e. the behaviour completeRegistration
has, be it a redirection to another page, perform an additional request, save a cookie, etc). So, you would be mocking the API that is being used in completeRegistration
but not the method itself.
That being said, if you want to check that completeRegistration
is being called you still have a couple of options.
You'll have to install the plugin and add it to your babel configuration. Once you have done so, your test would look like:
import AuthModule from '../../actions/auth';
import * as auth from '../../actions/auth';
describe('verifyEmail action', () => {
let verifyData;
beforeEach(() => {
verifyData = {
originalCode: '1234546',
confirmCode: '1234546',
token: '87618g1u8ojb98k3jb12i3kwdbcjwvbbi92ueg29eubv'
};
moxios.install();
});
afterEach(() => {
moxios.uninstall();
});
it('calls completeRegistration function if successful', async () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: { success: true }
});
});
const mockFn = jest.fn();
AuthModule.__Rewire__('completeRegistration', mockFn);
const store = mockStore({ payload: {} });
await store.dispatch(auth.verifyEmail(verifyData));
expect(mockFn).toHaveBeenCalled();
AuthModule.__ResetDependency__('completeRegistration');
});
});
You can create a separate module for completeRegistration
function. In this way, as your auth.js will have to import the module, you will be able to mock the module using jest.mock
capabilities.