My Jests tests are leaking memory, how can I fix this?
Asked Answered
B

9

35

When I run my jest tests, the amount of memory used per test increases over time. The issue wasn't apparent on my local machine; instead, I found this out when running my tests on CircleCI. I got the following error:

 FAIL  __tests__/pages/login.test.tsx
 
  ● Test suite failed to run
 
    jest: failed to cache transform results in: /tmp/jest_2ne/jest-transform-cache-7bdebd1a0c578519274d14a78b89f87c-f8238a99880aac6151736010e575fab1/0b/symbols_0bf4cffb45cb261625f2f3fca21a4789.map
 
    Failure message: ENOMEM: not enough memory, write
 
      at writeFileSync (node_modules/write-file-atomic/index.js:215:10)
      at writeCacheFile (node_modules/@jest/transform/build/ScriptTransformer.js:809:33)
      at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:554:7)
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:586:40)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:624:25)

How can I fix my jest configuration to prevent this?

Backward answered 13/7, 2020 at 22:41 Comment(1)
Could you solve it? if not, could you upload your package.json?Telling
B
35

First of all, make sure that you have leaky tests by running jest with the option: jest --logHeapUsage

Run your tests and check that the memory consumption is increasing over time, like this (file names changed):

PASS  __tests__/pages/file.test.tsx (181 MB heap size)
 PASS  __tests__/pages/file2.test.tsx (193 MB heap size)
 PASS  __tests__/components/Header/file3.test.tsx (201 MB heap size)
 PASS  __tests__/components/Header/file4.test.tsx (192 MB heap size)
 PASS  __tests__/components/Header/file5.test.tsx (218 MB heap size)
 PASS  __tests__/pages/file6.test.tsx (201 MB heap size)
 PASS  __tests__/components/file6.test.tsx (203 MB heap size)
 PASS  __tests__/components/file7.test.tsx (213 MB heap size)
 PASS  __tests__/components/file8.test.tsx (234 MB heap size)
 PASS  __tests__/components/file9.test.tsx (222 MB heap size)
 PASS  __tests__/components/file10.test.tsx (240 MB heap size)
 PASS  __tests__/components/file11.test.tsx (231 MB heap size)
 PASS  __tests__/utils/file12.test.tsx (239 MB heap size)
 PASS  __tests__/components/file13.test.tsx (251 MB heap size)
 PASS  __tests__/components/file14.test.tsx (239 MB heap size)
 PASS  __tests__/components/file15.test.tsx (249 MB heap size)
 PASS  __tests__/components/file16.test.tsx (143 MB heap size)

To fix this, change your npm run test or yarn test command in your package.json to: node --expose-gc ./node_modules/.bin/jest --runInBand --logHeapUsage

Run the command. Here's my output:

 PASS  __tests__/components/file.test.tsx (143 MB heap size)
 PASS  __tests__/pages/onboarding/file1.test.tsx (149 MB heap size)
 PASS  __tests__/components/file2.test.tsx (146 MB heap size)
 PASS  __tests__/components/file3.test.tsx (146 MB heap size)
 PASS  __tests__/components/file4.test.tsx (153 MB heap size)
 PASS  __tests__/components/Header /file5.test.tsx (149 MB heap size)
 PASS  __tests__/pages/file6.test.tsx (149 MB heap size)
 PASS  __tests__/pages/file7.test.tsx (149 MB heap size)
 PASS  __tests__/components/file8.test.tsx (147 MB heap size)
 PASS  __tests__/components/file9.test.tsx (148 MB heap size)
 PASS  __tests__/pages/file10.test.tsx (148 MB heap size)
 PASS  __tests__/components/Header /file11.test.tsx (148 MB heap size)
 PASS  __tests__/functions/file12.test.tsx (149 MB heap size)
 PASS  __tests__/components/file13.test.tsx (148 MB heap size)
 PASS  __tests__/components/file14.test.tsx (150 MB heap size)
 PASS  __tests__/components/file15.test.tsx (150 MB heap size)
 PASS  __tests__/components/Header /file16.test.tsx (149 MB heap size)
 PASS  __tests__/components/file17.test.tsx (149 MB heap size)
 PASS  __tests__/utils/file18.test.tsx (150 MB heap size)
 PASS  __tests__/components/file19.test.tsx (149 MB heap size)
 PASS  __tests__/pages/file20.test.tsx (150 MB heap size)

As you can see, the memory consumption is much more consistent.

You can read more about this issue and the solution in this Github issue, which describes a leaky garbage collector issue with jest.

Backward answered 13/7, 2020 at 22:41 Comment(0)
W
22

I was facing the same issue when running integration tests, where initially the heap size was about 160MB and it climbed up to ~1600MB locally and went OOM in CI. This issue also caused random tests to start failing with Exceeded timeout of 5000 ms for a test.
The main discussion for this issue can be found here where at the top you can find a quick fix for it. For the fix you'd have to set the workerIdleMemoryLimit flag in your config:

// jest.config.js

/** @type {import('jest').Config} */
const config = {
    workerIdleMemoryLimit: '512MB',
};

module.exports = config;

Environment:

  • node: 16.15.0
  • jest: 29.5.0
  • ts-jest: 29.0.5

After changes in config, the heap size stayed below the limit and fixed the timeout fails.
As an added bonus the tests ran faster locally ~20s and in CI ~4m (using --maxWorkers 4 cli option)

Weingarten answered 27/3, 2023 at 15:41 Comment(2)
after spending 3 days, only this solution works :)Snowonthemountain
This is the only solution that worked for me. thanks! Do you know how it works?Fractocumulus
P
12

You can use jest -w 1 to avoid these memory issues.

More information on Jest CLI documentation

--maxWorkers=|# Alias: -w. Specifies the maximum number of workers the worker-pool will spawn for running tests. In single run mode, this defaults to the number of the cores available on your machine minus one for the main thread. In watch mode, this defaults to half of the available cores on your machine to ensure Jest is unobtrusive and does not grind your machine to a halt. It may be useful to adjust this in resource-limited environments like CIs but the defaults should be adequate for most use-cases.

Polacca answered 8/7, 2021 at 19:47 Comment(0)
F
7

My environment is:

  • Node 18.12.1
  • Jest 29.3.1
  • ts-jest 29.0.3

My npm script to run the test is jest --coverage. When I run the test I get this error

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Using v8 as a coverage provider works for me.

// Example jest.config.js
module.exports = {
    coverageProvider: 'v8', // Default is 'babel'
    transform: {
        '\\.[jt]sx?$': 'ts-jest'
    }
};

Ref. https://jestjs.io/docs/configuration#coverageprovider-string

Forsythe answered 6/1, 2023 at 3:47 Comment(1)
Heads up: leaking memory and running out of memory are two different things. Your environment is running out of memory.Backward
A
4

In my case, it happened when I used a complex object:

expect(spyFn).toHaveBeenCalledWith(COMPLEX_OBJECT_WITH_DIFFICULT_STRUCTURE);

So you can get heap out of memory error when you use jest toEqual utility (it compares recursively all properties of object).

As a solution try to replace "complexObject" with "simplifiedObject":

  • expect.objectContaining({ ...someOfComplexObjectProps })
  • expect.any(Object)
Altair answered 26/10, 2022 at 10:59 Comment(0)
K
3

I tried a few different solutions that didn't work for me:

  • increasing --max-old-space-size
  • using the node flag: node --no-compilation-cache
  • use --runInBand
  • use --expose-gc
  • limiting the number of workers

What did work for me:

Limiting the idle memory per worker

I'm also limiting the number of workers so maybe it was a combination of the solutions.

Killifish answered 5/7, 2023 at 19:25 Comment(0)
C
2

Switching to node version 16.10 fixed the issue for me. Apparently, the memory leak with jest only happens with node version > 16. I simply used NVM to first install node 16.10 by running nvm install 16.10. After doing this, running my jest tests used 555MB as opposed to 1.5GB of memory.

Consolatory answered 19/10, 2022 at 10:39 Comment(2)
downgrading shouldnt be an optionSubsumption
This shouldn't be the accepted solution but it does shine light on a problem. I experienced the same issue going from node14 -> node16 -> node18 where memory appeared to be collected less frequently, and I could observe large jumps where memory would be deleted by the GB (going from 3000MB -> 1600MB for example).Seringa
A
2

In case it helps anyone else:

What didn't work for me:

  • --max-old-space-size
  • --no-compilation-cache
  • --runInBand
  • --expose-gc
  • --maxWorkers
  • --workerIdleMemoryLimit

What did work in the end:

  • --clearMocks

(Same result to add jest.clearAllMocks() to the beforeEach on each suite)

Went round the houses on this one - workerIdleMemoryLimit only seemed to work between suites rather than between each test (as per the docs) so also got it working by setting this and splitting up my larger suites, but was not happy with that as a final fix.

Affecting answered 14/3 at 8:49 Comment(0)
M
2

I have tried many things mention as above and others solutions but did not work,please do below config it will work fine if still not work upgrade node will help.

this will help in two things speeding test run and resolve heap memory

  1. add --workerIdleMemoryLimit=350 in jest command like below

    jest --env=jsdom --verbose a --coverage --max-old-space-size=16384 --silent --logHeapUsage --workerIdleMemoryLimit=350

change value of workerIdleMemoryLimit according you system configuration

  1. add isolatedModules: true in jest config transform property like below

    transform: { '^.+\.ts?$': ['ts-jest', { isolatedModules: true }] }

Marlie answered 22/3 at 16:59 Comment(1)
Adding isolatedModules: true to the ts-jest configuration dramatically reduced my heap usage and fixed this issue. Thank you, none of the other answers helped as much as this one.Mccloud

© 2022 - 2024 — McMap. All rights reserved.