I have several unit tests, and each module imports a lot of data resources from a JSON file via a method. This IIFE method is imported by every test module, and I'm trying to figure out why my tests are so slow. The JSON data is massive, so I'm guessing that the reason this is the case, is because every test imports the huge data as it is ran. If this is the case, I'll have to modify the method, to return only specific data sets.
So my question is, is the data imported every single time each test module runs, or only once when I execute npm run test
?
A basic example of the structure I have:
Codesandbox. Say test1.js
requires only dataset_1
key from the data json, and the other two test files need dataset_2
. Would it be more performant to write a method that returns the required data props to the test file that it is invoked in, or it doesn't matter? Trying my best to phrase this question correctly, please let me know what else I can clarify.
I have several unit tests, and each module imports a lot of data resources from a JSON file via a method. This IIFE method is imported by every test module, and I'm trying to figure out why my tests are so slow. The JSON data is massive, so I'm guessing that the reason this is the case, is because every test imports the huge data as it is ran. If this is the case, I'll have to modify the method, to return only specific data sets.
So my question is, is the data imported every single time each test module runs, or only once when I execute npm run test
?
A basic example of the structure I have:
Codesandbox. Say test1.js
requires only dataset_1
key from the data json, and the other two test files need dataset_2
. Would it be more performant to write a method that returns the required data props to the test file that it is invoked in, or it doesn't matter? Trying my best to phrase this question correctly, please let me know what else I can clarify.
- 1 Modules should be imported only once, but it depends on your test package and structure... about data loading it's impossible to answer without the code. – Daniele Ricci Commented Jun 18, 2020 at 8:44
- Could you share what test runner you are using? – Drag13 Commented Jun 18, 2020 at 9:17
3 Answers
Reset to default 7 +100Yup, I think you need to update your tests. This is what the docs say, in the resetModules
configuration switch section:
... each test file gets its own independent module registry.
This tallies with the behaviour I've observed. For each test file the whole runtime is rebuilt, meaning all modules are imported from scratch. That makes sense, because it means that mon test bugs related to mutable global state not being cleaned up between tests are eradicated.
Also, it's worth noting jest can (if not always does) use subprocesses to run each test, so that it can be parallelized more easily, which is another reason why it makes sense to do a pletely fresh setup for each test file. You can switch this off by using --runInBand
, but that doesn't change the behaviour, see the example below.
On a default install, you can see the problem by simply putting a console.log()
statement in an import file, and then having two tests import it, something like:
mylib.js
console.log('Hello from mylib.js!');
jests/test1.js
const mylib = require('../mylib');
describe('test1', () => {
it('should be equal', () => {
expect(1).toEqual(1);
});
});
jests/test2.js
const mylib = require('../mylib');
describe('test2', () => {
it('should be equal', () => {
expect(2).toEqual(2);
});
});
I get output along the lines of:
3.2: npm run jest -- --runInBand jests/test*
> [email protected] jest /path/to/cwd
> jest "jests/test1.jest.js" "jests/test2.jest.js"
(node:60746) ExperimentalWarning: The fs.promises API is experimental
PASS jests/test1.jest.js
● Console
console.log
Hello from mylib.js!
at Object.<anonymous> (mylib.js:1:9)
PASS jests/test2.jest.js
● Console
console.log
Hello from mylib.js!
at Object.<anonymous> (mylib.js:1:9)
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.075 s
Ran all test suites matching /jests\/test1.jest.js|jests\/test2.jest.js/i.
I don't know how it imports data and how it works. But whenever you write test cases your data should not be huge. Actually we only need to test the functionality or role of any ponent, is it working according to our flow design or not. That's it. So your data for test cases should be small in amount.
From node.js side, no reload problem at all. JSON files are read and parsed only once, then cached and the cached version is returned for each require
call. Pay attention, what is cached it the parsed JavaScript Object, so if cached version is changed, next require
call will returns the changed version.
From jest side, there could be a reload problem; reading at the doc, it seems that without the --runInBand option more processes are launched: you could try it to check if it solves your problem.
As last chance you can trust require
cache and test if by yourself: only for this test purpose you can change the cached version in test1.js
and check if cached version is still changed in test2.js
, if it is still changed: no, the source of your problem is somewhere else, if changes applied in test1.js
are lost: yes, you are reloading (and reparsing) the entire json file.
Hope this helps.