Introduction
In the previous article, Potential issues with barrel files in Webpack, we discussed the potential issues of using barrel files in Webpack. In this article, we will focus on the issues of using them in Jest tests.
For a comprehensive understanding of barrel files and their use cases, I recommend reading the previous article.
Barrel files in Jest
Unlike Webpack, Jest does not have a tree shaking feature. This means that when you import modules through barrel files, Jest will include all the exported modules from barrel files in your tests, even those that are not used. This behavior can lead to two significant issues: slow performance and unexpected test results.
Issues
1. Performance Impact
One of the most common complaints from developers who use Jest often report slow test execution times when their code includes barrel files #1. While this might not be noticeable in smaller projects, it becomes a significant issue in larger ones.
This issue arises because Jest needs to load all the modules exported from a barrel file, regardless of their usage. This can significantly increase loading time, especially if the barrel file contains numerous modules.
Example
To illustrate this issue, let's consider the perf-impact example repository.
In this repository, we want to test the Javascript file indirect-import.js that imports only the Reexported1
specifier from a barrel file index.js, which re-exports 100 modules.
Let's create a test for this file named indirect-import.test.js and run npm run test
and observe the performance.
The test execution takes an average of 2.865 seconds, which is significant for a single test. Imagine the time it would take for hundreds of tests relying on barrel files!
Why is it slow? When importing from barrel files, Jest loads all the modules, even unused ones, impacting performance.
We need a solution for this poor test performance.
Solution
One solution could be to avoid using barrel files altogether, but this would negatively impact our developer experience.
Another solution can be using a tool that will automatically transform indirect imports to direct imports.
To address this, I developed a Babel plugin, babel-plugin-transform-barrels
, that transforms indirect imports (through barrel files) into direct imports.
Let's apply the babel-plugin-transform-barrels
plugin solution as follows:
- Clone the perf-impact repository to a new
perf-impact-with-barrel-plugin
repository. - Install the
babel-plugin-transform-barrels
plugin. - Copy the
babelTransform.js
file into the folderconfig\jest
. - Adapt the
babelTransform.js
file to the current repository. - In the
jest.config.js
file, reference thetransform
object to thebabelTransform.js
file instead of theregularTransform.js
file. - Run the command
npm run test
.
Now, see that the test time dropped from 2.865 seconds to 1.31 seconds, which is a reduction of more than 50%. This improvement is very significant!
Note
The above steps have been implemented in the perf-impact-with-barrel-plugin repository.
Now that we’ve addressed the performance issue, let’s move on to the next issue.
2. Unexpected Test Results
Another issue can arise when we import a module from a barrel file that contains unused modules, some of these unused modules can affect the test results in unexpected ways.
Example
To illustrate this issue, let's consider the unexpected-results example repository.
In this repository, we want to test the Javascript file indirect-import.js that imports only FirstReexported
specifier from a barrel file index.js, which re-exports all the specifiers from the Reexported
and DropFiles
modules.
Let's create a test for this Javascript file named indirect-import.test.js and run npm run test
.
We can see that the test failed. As we can see in the details of the test's result, the failure is caused by the module DropFiles
.
But why did the test fail because of an unused module that we didn't want to import? As mentioned earlier, when we import from a barrel file, all the re-exported modules will be loaded, even the unused modules.
Again, the barrel file caused a problem for us!
Solution
The solution here is the same as the previous example of perf-impact
. We need to transform the imports from indirect imports (through barrel files) to direct imports.
Let's do the same steps as the previous example.
Let's apply the babel-plugin-transform-barrels
plugin solution as follows:
- Clone the unexpected-results repository to a new
unexpected-results-with-barrel-plugin
repository. - Install the
babel-plugin-transform-barrels
plugin. - Copy the
babelTransform.js
file into the folderconfig\jest
. - Adapt the
babelTransform.js
file to the current repository. - In the
jest.config.js
file, reference thetransform
object to thebabelTransform.js
file instead of theregularTransform.js
file. - Run the command
npm run test
.
Now we can see that the test passes successfully!
Note
The above steps have been implemented in the unexpected-results-with-barrel-plugin repository.
Summary
While using barrel files can offer benefits for developer experience, it can also lead to performance issues and unexpected test results in Jest. To resolve them, use the babel-plugin-transform-barrels
plugin, which transforms indirect imports (through barrel files) into direct imports.
This plugin effectively maintains developer experience with test performance and reliability.
I hope this article has provided you a deeper understanding of the issues with using barrel files in Jest and how the babel-plugin-transform-barrels
can be a valuable tool in your testing toolkit.
Top comments (2)
Can we use babel-plugin-transform-barrels with jest tests written for an angular application?
Hi Anand
I haven't tried it with Jest tests written for an Angular app, but it should work.
If you have any issues, you can open one on the plugin's Github page and I'll help:
github.com/FogelAI/babel-plugin-tr....