Reputation: 803
let's say I have a module that needs to be initialized once in the start of the app (to pass on configuration). module will look something like this :
MyModule.js
let isInitiazlied;
const myModule = {
init: function() {
isInitiazlied = true;
},
do: function() {
if (!isInitiazlied)
throw "error"
//DO THINGS
}
}
export default myModule;
I want to unittest it, using jest. test file looks something like this :
MyModule.test.js
import myModule from './MyModule'
describe('MyModule', () => {
describe('init', () => {
it('not throws exception when called', () => {
expect(() => myModule.init()).not.toThrow();
});
})
describe('do', () => {
it('throw when not init', () => {
expect(() => myModule.do()).toThrow();
});
})
})
when I run the test, the 2nd test fail, as the module already initialized so the exception is not thrown. I tried using jest.resetModules() in beforeEach, but that didn't work.
Is there a way to solve it (different module pattern/test case) ?
Upvotes: 55
Views: 56750
Reputation: 1483
A solution that worked well for me and allowed me to continue using canonical top-of-the-file imports: I added a function
export function resetIsInitializedForTests() {
isInitialized = false
}
to MyModule.js
and then I called it inside beforeEach
in MyModule.test.js
.
Upvotes: 0
Reputation: 918
Resetting the process.env does not work very well with Jest across all Node platforms. After trying various options I realized there is a very simple fix to solve this issue using regular jest mock by adding a wrapper function for retrieving process.env. This will avoid having unexpected behaviors cross platforms.
Those who are new to Jest here is a complete solution. Add a JS file nodeEnvironment.js with the function as follows
const getNodeEnvironment = () => {
return process.env;
};
export default getNodeEnvironment;
Then import the getNodeEnvironment function as normally you would do.
import getNodeEnvironment from './nodeEnvironment';
const myMainFunction= () => {
const env = getNodeEnvironment();
const myVarVal = env.myVar
}
and then use the jest mock. Please note you will need to set esModule flag to true if you want your function to be default export and then add return default: mockvalue as follows.
jest.mock('./nodeEnvironment', () => ({
__esModule: true,
default: () => {
//here set all variables you need for your tests
const env = { myVar: "123" };
return env;
},
}));
Upvotes: -1
Reputation: 1341
You have to re-import or re-require your module. Check the doc or this issue for more information:
https://github.com/facebook/jest/issues/3236
https://jestjs.io/docs/jest-object#jestresetmodules
describe('MyModule', () => {
beforeEach(() => {
jest.resetModules()
});
describe('init', () => {
const myModule = require('./MyModule');
it('not throws exception when called', () => {
expect(() => myModule.init()).not.toThrow();
});
})
describe('do', () => {
const myModule = require('./MyModule');
it('throw when not init', () => {
expect(() => myModule.do()).toThrow();
});
})
})
Upvotes: 71
Reputation: 21
In my case only re-requiring didn't work. I got through jest documentation and found this. This suggest use of jest.resetModules(). This basically just resets the cache and on re-requiring module it makes sure it gets loaded from scratch. So when ever you want are re-requiring use this to make sure the it is getting loaded from scratch
Upvotes: 0
Reputation: 5408
@ltamajs solution is great for require
but in the case you are using import
then you will receive the next error.
SyntaxError: /path/to/test/file.js: 'import' and 'export' may only appear at the top level
To solve this issue, you can use the babel-plugin-dynamic-import-node
plugin and then reset the modules. Overall, it looks like this:
describe('MyTests', () => {
let MyModule;
beforeEach(() => {
return import('../module/path').then(module => {
MyModule = module;
jest.resetModules();
});
});
test('should test my module', () => {
expect(MyModule.aMethod).not.toBeUndefined();
});
});
Source: https://github.com/facebook/jest/issues/3236#issuecomment-698271251
Upvotes: 19