Optimizing Unit Testing in JavaScript: Tips, Tools, and Best Practices
Tags: unittest, jest, testing, bestpractices
Published: 2023-01-29 06:37:52

---
title: Optimizing Unit Testing in JavaScript: Tips, Tools, and Best Practices
published: true
date: 2023-01-24 08:50:32 UTC
tags: unittest,jest,testing,bestpractices
canonical_url: https://thesametech.com/optimizing-unit-testing-javascript-tips-tools-best-practices/
---

![](https://cdn-images-1.medium.com/max/1024/0*Ak7jMrTFp5w_MCYT.png)

In this article, we will focus on optimizing unit testing in JavaScript. We will discuss some of the best tools for unit testing such as Jest, jest-circus, and React Testing Library (RTL) and show you how to configure these tools for optimal performance. We’ll also provide tips and best practices for improving your testing workflow, so you can ensure that your code is reliable and working as expected. Whether you’re a seasoned developer or just getting started with unit testing, this guide will help you improve your testing process and produce high-quality code.

### Unit tests

I prefer to use the following tools for unit testing:

- [Jest](https://jestjs.io/). It’s a JavaScript testing framework that can be easily integrated with any other testing and development tool.
- `jest-circus` test runner built on top of Jest and providing parallelized execution capabilities for tests. Starting with Jest v27, it comes as the default test runner in jest configuration.
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/). It’s a go-to tool for testing React components. I used to have Enzyme on this list a few years ago but unfortunately, it’s not maintained anymore and I highly don’t recommend using it in your project. You can read about the strategy and tools I use to migrate projects from Enzyme to RTL in my [article](https://thesametech.com/migrate-away-from-enzyme/).

### Configuration

**React Testing Library setup**

JSDOM’s implementation of `getComputedStyle()` is super slow. As I do not usually do any style-specific assertions and validations in my unit tests, I prefer to mock this API to speed up RTL tests by up to 2x.

```
// somewhere in your setup file
global.getComputedStyle = () => {
  return {
    getPropertyValue: () => {
      return undefined;
    },
  };
};
```

Alternatively, you can switch from JSDOM implementation to LightDOM. You can try both approaches together as well.

**No network calls**

Network calls in unit tests might significantly slow down test performance. There is an easy solution for this: `jest-offline` library. It will fast-fail all tests that attempt to access the network. If you are using `fetch` API in your project then `jest-fetch-mock` will automatically mock all API requests for you:

```
import { enableFetchMocks } from 'jest-fetch-mock'; 

enableFetchMocks();
```

But some third-party libraries might use different mechanisms to integrate with the network API (good old XHR requests, for instance). Therefore, I prefer to use these 2 tools together — they perfectly complement each other.

**Transpiler**

If you are using `babel-jest` or `ts-jest` in your Jest configuration to transpile JavaScript/TypeScript files, then I have bad news for you - they will slow down your tests too! Nowadays, cool kids use `swc/jest` or `esbuild` transpilers that are written by faster Rust and Go languages respectively. It's easy to switch - highly recommend you do it right away. Really a low-hanging fruit for improving your test performance.

### Tools

Use `jest-slow-test-reporter` to identify what tests are the slowest! Usually, you will get a significant performance boost by addressing just a small portion of your tests. My rule of thumb is unit test execution time should not exceed 300ms.

### Local development

**Commands:**

```
   "test": "TZ=America/Los_Angeles LANG=en_US.UTF-8 jest --config jest.config.json --passWithNoTests --maxWorkers=50%",
   "test:bail": "npm test -- --bail",
   "test:diff": "npm test -- -o --watch",
   "test:clean": "jest --clearCache"
```

**Hints:**

`TZ=America/Los\_Angeles LANG=en\_US.UTF-8` environment variables are needed to lock dates and timezones - crucial when you have Node v14+ and use date-fns-tz in your code.

`--maxWorkers=50%` usually help to improve test performance by 20% but requires careful benchmarking. Inspired by this [article](https://dev.to/vantanev/make-your-jest-tests-up-to-20-faster-by-changing-a-single-setting-i36).

I prefer to use JSON file (`jest.config.json`) for configuration rather than `.js` or `.ts`. Reason: `jest` is requesting `ts-node` from the transpiling of `jest.config.ts`. For TypeScript file improvement usually 2X, for JS files it's pretty much the same as JSON.

`--bail` command is useful when you need to do a quick sanity check whether all tests are still passing - run tests until the first fails. If fails, use a more suitable command for continuous troubleshooting and fixing the tests.

`test:diff` will run only tests for files staged in your local Git workspace and will do it in watch mode. This is the most popular command in my arsenal that I usually run while I refactor some existing code (for example, re-writing React class component to functional component). With good coverage and well-written test code, it's super easy to catch regressions.

### Submitting code review

If you still don’t use `husky` and `lint-staged` as part of Git pre-commit hook integration, then you should. Here is the configuration I usually have:

```
  "lint-staged": {
    "*.{js,jsx}": [
      "eslint -c ./.eslintrc.js --fix",
      "git add",
      "npm test -- --findRelatedTests"
    ]
  }
```

`npm test -- --findRelatedTests` will run only tests related to files that have changed. You can read more about how it works in one of my previous [articles](https://thesametech.com/under-the-hood-jest-related-tests/).

### Storybook

If your project uses StoryBook to run your components in isolation (let’s say you have an internal UI library), then you can also include `start-storybook --smoke-test` to your pre-commit configuration - it will execute dry-run of the start command and fail immediately if something is wrong (maybe you have some breaking change in the component contract?).

Also, you can use storyshot add-on to automatically cover all components in your UI library with snapshot tests.

### Continuous integration (CI)

**Command**

```
"test:ci": "npm run test -- --runInBand"
```

According to this GitHub [issue](https://github.com/facebook/jest/issues/8202), `--runInBand` performs better in CI environments rather than local ones due to the resource constraints of such environments. Basically speaking, with `runInBand` we tell Jest to run tests serially rather than orchestrate a thread pool of test workers. Please benchmark it if you can - from my previous experience, "it depends". I guess I was lucky enough to have powerful CI machines.

### Conclusion

In conclusion, unit testing is a crucial part of software development that ensures the quality and reliability of your code. By choosing the right tools and configuring them properly, you can improve the performance of your tests and streamline your testing workflow.

* * *

_Originally published at_ [_https://thesametech.com_](https://thesametech.com/optimizing-unit-testing-javascript-tips-tools-best-practices/) _on January 24, 2023._

_You can also_ [_follow me on Twitter_](https://twitter.com/mastershifu89) _and_ [_connect on LinkedIn_](https://www.linkedin.com/in/isharafeev/) _to get notifications about new posts!_