Jest is my current choice for unit testing JavaScript and TypeScript projects (using ts-jest). I particularly like that it has everything baked in and does not require separate assertion or mock libraries. However, one thing that I was not particularly fond of was the speed.

The Problem

On a recent TypeScript project (a small library of utility functions), I started to notice that my unit tests were taking much longer than expected. This project is new, relatively small, an only contained 38 unit tests across 5 files. The run would consistently take over 16 seconds to complete on a development machine with extremely high-end specs.

Test Suites: 5 passed, 5 total
Tests: 38 passed, 38 total
Snapshots: 0 total
Time: 16.586 s

I tried a lot of things in my jest.config.ts file, including limiting the search folder to only look in my src directory, and even reordered the moduleFileExtensions to include TypeScript files first per the Jest documentation.

import type { InitialOptionsTsJest } from 'ts-jest/dist/types';

const config: InitialOptionsTsJest = {
globals: {
'ts-jest': {
},
},

preset: "ts-jest",
displayName: "OSAS-TypeScript",
testEnvironment: "node",
roots: ["<rootDir>/src/"],
testMatch: ["**/*.Tests.ts?(x)"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
};

export default config;

The file above is what I ended up with, but the tests still took around 16 seconds to run.

The Solution

After much searching, I found a lot of people have the same issue, and a lot of suggestions of things to try. Most actually didn’t have any affect on the speed, but two configuration changes did.

I modified my jest.config.ts file with the two options highlighted:

import type { InitialOptionsTsJest } from 'ts-jest/dist/types';

const config: InitialOptionsTsJest = {
globals: {
'ts-jest': {
isolatedModules: true,
},
},

preset: "ts-jest",
displayName: "OSAS-TypeScript",
testEnvironment: "node",
roots: ["<rootDir>/src/"],
testMatch: ["**/*.Tests.ts?(x)"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
maxWorkers: "50%",
};

export default config;

Just those changes yielded a 95% increase in speed with the test run now consistently running in under a second.

Test Suites: 5 passed, 5 total
Tests: 38 passed, 38 total
Snapshots: 0 total
Time: 0.767 s

So What’s the Catch?

maxWorkers: “50%”

There isn’t really a catch to this setting. It reduces the default number of simultaneous threads used to run tests which, in most cases, yields better performance. In fact, in most cases it yields a 20% increase in performance by itself.

isolatedModules: true

This setting does have a significant caveat - it compiles each file separately which disables type-checking and some other features but, as you can see, results in a huge performance boost. This may or may not be what is needed for your project, so use accordingly.

© 2024 OCERIS, Inc. All rights reserved.