Potential issues with barrel files in Jest
Tags: javascript, jest, testing
Published: 2024-05-22 09:02:23

## Introduction

In the previous article, [*Potential issues with barrel files in Webpack*](https://dev.to/fogel/potential-issues-with-barrel-files-in-webpack-4bf2), 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](https://github.com/jestjs/jest/issues/11234). 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](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/perf-impact)* example repository.
In this repository, we want to test the Javascript file *[indirect-import.js](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/perf-impact/src/indirect-import.js)* that imports only the `Reexported1` specifier from a barrel file *[index.js](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/perf-impact/src/components/index.js)*, which re-exports 100 modules.

Let's create a test for this file named *[indirect-import.test.js](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/perf-impact/src/indirect-import.test.js)* and run `npm run test` and observe the performance.


![Execution time without a Babel plugin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt0gtpk73abnfugzmy9p.PNG)

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`](https://github.com/FogelAI/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:

1. Clone the *[perf-impact](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/perf-impact)* repository to a new `perf-impact-with-barrel-plugin` repository.
2. Install the [`babel-plugin-transform-barrels`](https://github.com/FogelAI/babel-plugin-transform-barrels) plugin.
3. Copy the [`babelTransform.js`](https://github.com/FogelAI/babel-plugin-transform-barrels/blob/main/config/jest/babelTransform.js) file into the folder `config\jest`.
4. Adapt the `babelTransform.js` file to the current repository.
5. In the `jest.config.js` file, reference the `transform` object to the `babelTransform.js` file instead of the `regularTransform.js` file.
6. Run the command `npm run test`.


![Execution time with a Babel plugin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twmzichiolg3fqeiuqx1.PNG)

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](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/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](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/unexpected-results)* example repository.
In this repository, we want to test the Javascript file *[indirect-import.js](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/unexpected-results/src/indirect-import.js)* that imports only `FirstReexported` specifier from a barrel file *[index.js](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/unexpected-results/src/components/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](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/unexpected-results/src/indirect-import.test.js)* and run `npm run test`.


![Test failed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wayhilq3pjihshczwim.PNG)

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:

1. Clone the *[unexpected-results](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/unexpected-results)* repository to a new `unexpected-results-with-barrel-plugin` repository.
2. Install the [`babel-plugin-transform-barrels`](https://github.com/FogelAI/babel-plugin-transform-barrels) plugin.
3. Copy the [`babelTransform.js`](https://github.com/FogelAI/babel-plugin-transform-barrels/blob/main/config/jest/babelTransform.js) file into the folder `config\jest`.
4. Adapt the `babelTransform.js` file to the current repository.
5. In the `jest.config.js` file, reference the `transform` object to the `babelTransform.js` file instead of the `regularTransform.js` file.
6. Run the command `npm run test`.


![Unexpected results example with a Babel plugin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xt21jfyrfwoemvndwqga.PNG)

Now we can see that the test passes successfully!

**Note**
The above steps have been implemented in the *[unexpected-results-with-barrel-plugin](https://github.com/FogelAI/jest-barrel-issues-article/tree/main/examples/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`](https://github.com/FogelAI/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`](https://github.com/FogelAI/babel-plugin-transform-barrels) can be a valuable tool in your testing toolkit.