I am trying to mock an external module (jwt_decode for those interested), and I have seen many examples of how to mock external an node module using Jest both for all tests in a test suite, as well as on a per-test basis.
I have been able to mock the dependency so that it mocks the return value for all tests in the suite, although the default function is all that i'm really concerned with.
import jwt_decode from 'jwt-decode';
jest.mock('jwt-decode', () => jest.fn().mockReturnValue({
exp: 12345,
somethingElse: 'test_value'
}));
This works well, except I would like to test a scenario where the returned token has expired, so that I can verify that certain Redux actions were dispatched when this situation arises.
import jwt_decode from 'jwt-decode';
const decoded = jwt_decode(localStorage.jwtToken);
// set user info and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// this is the scenario I am looking to test
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
store.dispatch(logoutUser());
store.dispatch(clearCurrentProfile());
window.location.href = '/login';
}
I would like to modify the returned mock for an individual test so that I can ensure that the 'if' statement shown equates to false, and other parts of the code base are executed.
How can one go about this?
Some of the examples I have tried and failed with so far include:
test('some test that will use a different mock' () => {
// re-assign value of the imported module using the its given alias
jwt_decode = jest.fn().mockImplementation(() => {
return {
exp: 'something_different 9999999999',
somethingElse: 'I_changed_too'
};
});
});
As well as
jwt_decode.default = jest.fn().mockImplementation(() => {
return {
exp: 'something_different 9999999999',
somethingElse: 'I_changed_too'
};
});
And also jest.spyOn(), as seen in this SO question, as well as A Jar of Clay's answers on the same question, which proposes the following:
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// ...
});
I also found a suggestion for creating a util which changes the global localStorage on a test by test basis, but I would rather not use a real jsonwebtoken, or have to worry about storing sign-in credentials.
What I keep ending up with is that jwt_decode is not updated when running the test that should have the different mock value returned, or what's more common is that I get an error saying that ".default is not a function".
If you have suggestions, I would be very grateful.