Jest: Jest process doesn’t quit after last test completes

Created on 18 Aug 2016  ·  60Comments  ·  Source: facebook/jest

I’m having issues with the Jest process not completing after the last test completes. The user will have to force quit the process with ctrl-c. My theory is that not all resources are being cleaned up appropriately by the test authors, but ideally Jest should quit anyway.

Specifically I’m testing Firebase with firebase-server, spinning up one or more servers for every test. In an afterEach action we call the close method for all the servers created in the last test, however even with this method the Jest process still doesn’t quit.

Is there a way to force the Jest process to quit once tests have finished (pass or fail)? Is there a way to get an afterAll hook to cleanup all leftover resources? Is there a way to debug what exactly keeps the Jest process from quitting? Thanks.

Enhancement Help Wanted good first issue

Most helpful comment

for anyone reading you can use --forceExit flag to access this functionality. 🎉

All 60 comments

We don't have a good way to do that right now. I would recommend trying to hook in a debugger (Chrome Inspector) to figure out what is going on. If you know what creates the async work, you can potentially also monkey patch it and track it (like put something around Promise.prototype.then)

Is there a reason async work can’t be force quit when all afterEach/after hooks have resolved?

I don't know how you'd kill existing async processes if you don't have a handle on them.

I migrated from ava and this wasn’t a problem, so maybe there is an answer? Maybe that’s process.exit in Node.js

We could do that, I guess, but I'm worried it leaves people not hanging when it should and they aren't shutting down their resources properly.

cc @dmitriiabramov what do you think?

One example: I actually ran into this with Jest myself where we had a long running watcher process that wouldn't terminate Jest itself. If Jest would have killed itself during the test run (heh!) I would have never noticed the issue and I would have shipped a version that would hang when people try to use it.

i'm not sure if it's safe to force kill the process. at the same time, if people want to do some async post processing after the tests are done, they could use after all hook that will wait for it to finish before quitting the process.

the other issue that we might have is cutting the output stream before it finished printing. we had this issue before, when error messages don't have enough time to print before the process exits.

The question is whether we could figure out a way for Jest to say "Looks like some tests aren't cleaning up after themselves. here is what is going on".

An after all hook could help me here, but I haven’t seen such a thing in the documentation (only afterEach) am I missing anything?

As for testing correct cleanups, if you could test if _files_ were completing on time and if they weren’t using a bisect feature to isolate the problem (like in rspec).

Ok, so after more research this appears to be a problem with Firebase itself, and there is no way to cleanup short of calling process.exit.

Resources:

All of the workarounds involve manually calling process.exit. I’m afraid to do this in a Jest context, is there a recommendation on where to put such a call? My first thought was something like:

afterAll(() => setTimeout(() => process.exit(), 1000))

…to exit one second after all tests finished running to let Jest do its thing, however I’m not sure how this affects watch mode, and if I’m correct Jest does some fancy parallelism stuff which might make this not work as expected. Alternatively, would this be something you need to fix in Jest proper? If this seems like a footgun for a number of people, why not put it into Jest? Or at least a toggle between “warn” mode and “kill” mode.

i'd love a --exit flag or something (it could be a per-file comment or something) that automatically closes the processes when tests complete, similar to mocha. it's a little annoying to manually close every connection in every test file.

I'm having the same problem when I run tests in Codeship. It also fails on drone.io.
Locally it works properly though.

EDIT:

  • Jest version: 15.1.1
  • Local:

    • Node: 6.2.2

    • npm: 3.9.5

  • CodeShip:

    • Node: 6.5.0

    • npm: 3.10.3

  • Drone.io

    • Node: 0.10.26

    • npm: 1.4.3

It seems to me like Firebase should be fixed.

I have no reservations against adding an option called --forceExitAfterTestRun and it should be easy to add. I think it just requires a change to exit here: https://github.com/facebook/jest/blob/master/packages/jest-cli/src/cli/index.js#L41 if the flag is given regardless of the result.

Seems to be a race condition of sorts. Sometimes it quits after running all test locally sometimes it doesn't...

I'm running this as well after starting to use Jest for my API specs where I'm using real database instead of mocks (sorry 😇 but snapshots are great for this). I yet been able to solve the issue even after adding afterAll hooks to clean up connections which leads me to believe it's some how related to my population of fixtures in setupFiles, not the easiest to debug.

Jasmine seems to have --forceexit option so I would not complain if similar would also land to Jest 🙏

another issue - if a test fails, then afterAll() isn't called, so nothing is cleaned up and nothing closes. i think --bail will fix this but i haven't tried that yet

If anyone would like to send a PR, this is something that we could use some help with and I outlined details in my previous comment :)

I'll give it a shot if I get some time over the weekend. If someone wants to do it before that it'd cool :smile:

Closing in favor of the PR that was just opened. We'll continue the discussion there.

for anyone reading you can use --forceExit flag to access this functionality. 🎉

For googlers: Jest does not exit on Jenkins CI, while it does locally.. --forceExit indeed fixed it for me.

For me it was forgetting handling promise with .then(() => {}) - did the job

I'm still struggling with this. I'm testing an API with async and await. I connect to my express application and ping an endpoint but the test doesn't close. I've tried to close the connnection to mongodb and to the server but it's still open. I'm only sending back empty json.

In my case this ended up being a Firebase issue. Using

afterAll(() => {
  firebaseApp.database().goOffline();
  firebaseApp.delete();
});

seems to do the trick. I've found that both lines are actually necessary and that you need to use the same firebaseApp that you originally get from .initializeApp().

Is there any way to solve this without forceExit?

Jest 23 includes a flag called --detectOpenHandles which should point to the source of why Jest is unable to exit

--detectOpenHandles returns mongoose.connect and mongoose.model. Trying to mongoose.disconnect in afterAll raises mongo error Topology destroyed.

screenshot 2018-06-08 11 14 51
screenshot 2018-06-08 11 14 29

@elkhan have u figure it out how to solve mongoose problems?

After adding --detectOpenHandles, not only does Jest complete my tests and also not showing anything that actually blocks Jest which is weird. Looks like a bug.

For me, --forceExit solves the problem, at the same time I use --detectOpenHandles but it detects nothing (both locally and on CircleCI). I'm also running with --runInBand.

For me, removing --runInBand solved it.

--forceExit solves the problem for me as well when using shippable ... Tried --detectOpenHandles but didn't give any results and still just caused the build to hang

Adding --detectOpenHandles fixes the issue, which is bizarre.

Node: v8.12.0
Jest: v23.6.0

Adding --detectOpenHandles or --forceExit doesn't fix the issue for me when running on Codeship.

jest --ci --verbose --forceExit --detectOpenHandle

Node: v8.12.0
Jest: v23.6.0

@sibelius a way of avoiding this issue is by muting the init function of the model

const mongoose = require('mongoose');

mongoose.Model.init = () => {};

This will stop Jest from complaining about the models, although indexes will not be created

db.collection("test-collection").add({
    title: 'post title',
    content: 'This is the test post content.',
    date: new Date(),
})
    .then(docRef => {
        console.log('Document written with ID: ', docRef);
    })
    .catch(error => {
        console.error('Error adding document: ', error);
    });

jest --forceExit --detectOpenHandle the tests are passed, but the code in.then or .catch does not run!!
any ideas?

@alexpchin Here's how I solved it:

    beforeAll(async (done) => {
        dbConnection = await mongoose.connect(...)
        done()
    })

    afterAll(async (done) => {
        await dbConnection.close()
        dbConnection.on('disconnected', done)
    })

With NestJs I had to add

afterAll(() => {
  app.close();
});

We found that this issue was caused by the jest process running out of memory. Adding --maxWorkers=10 fixed the issue for us.

I'm adding this cause maybe someone wondering into this issue might be having the reason for this as I had.
I was using Jest within Travis to test a NodeJS app and travis kept hanging until timeout directly after Jest. Appears Jest was not closing down.
After many tryes I discovered the reason was using jest with JSDom.
I had the following line in my jest.config.js file:

  'testURL': 'http://localhost/',

Which caused JSDom to load and supposedly not closing all resources gracefully and keeping Jest alive.

I solved it by removing the line - however Jest will then fail with the following error see this:

SecurityError: localStorage is not available for opaque origins

To solve it I added the following to jest.config.js:

  'testEnvironment': 'node',

Hope that helps anyone.I'm adding this cause maybe someone wondering into this issue might be having the reason for this as I had.
I was using Jest within Travis to test a NodeJS app and travis kept hanging until timeout directly after Jest. Appears Jest was not closing down.
After many tryes I discovered the reason was using jest with JSDom.
I had the following line in my jest.config.js file:

  'testURL': 'http://localhost/',

Which caused JSDom to load and supposedly not closing all resources gracefully and keeping Jest alive.

I solved it by removing the line - however Jest will then fail with the following error see this:

SecurityError: localStorage is not available for opaque origins

To solve it I added the following to jest.config.js:

  'testEnvironment': 'node',

Hope that helps anyone.

--forceExit --detectOpenHandles --maxWorkers=10

did it for us

node: 8.11.3
jest 23.6.0

With NestJs I had to add

afterAll(() => {
  app.close();
});

Just leaving this here for NestJS people:
With NestJS, I discovered that the answer above does work.
What DOESN't work is the following:

afterAll(async () => {
        await app.close()
    })

for me, it is --forceExit --maxWorkers=10 that works (I'm on Ubuntu 18.04, using [email protected])

In my case, using NodeJS 10 or 11 fix the issue, but it's still there with Node 6 ou Node 8. nothing is displayed when using --detectOpenHandles option, and --forceExit fix the issue too.

+1 more person here (like @motss and @seanlindo ) observing that the _"Jest did not exit one second after the test run has completed."_ occurs only when --detectOpenHandles is not used.

[email protected]

Tests fail consistently without --detectOpenHandles but pass and don't show any open handles when running with --detectOpenHandles.

The machine/container running the tests has two cores, but by default, tests are running with maxWorkers=1

When I add the --detectOpenHandles flag and look at the config/globalConfig using the --debug flag, the detectOpenHandles value is the _only_ difference...

If I run with --runInBand --detectOpenHandles tests still pass fine.

I can run using any of the following to finish tests successfully without showing the "...did not exit..." error:

  • jest --maxWorkers=2
  • jest --detectOpenHandles
  • jest --forceExit

Working around it with maxWorkers=2 for now, but those are my observations, just for anyone searching in the future...

_Edit: Additional detail: this only affects my CI environment, which is a docker container FROM alpine:3.7 running node v8.9.3. I cannot reproduce with --maxWorkers=1 on my dev machine_

Confirming I get this error right now. Using --maxWorkers=10 seems to fix the issue.

So.... I was fighting with this for quite some time (using travis ci, coveralls and typescript).
It would end up hanging and producing a failed build (but only w/in Travis CI).

After much trial and error, i found what fixed this for me was that I added in an explicit path to the tests.

It failed with the npm script

   "test": "jest",
    "test:coverage": "npm run test -- --collectCoverage && cat ./src/coverage/lcov.info | coveralls",

And passed (in travis ci) with:

   "test": "jest .*\.test\.ts",
    "test:coverage": "npm run test -- --collectCoverage && cat ./src/coverage/lcov.info | coveralls",

If you are using docker with a Redhat UBI image and create-react-app make sure you set CI=true before running npm test

December 2019. Ran into this issue ONLY on Travis. Tests pass locally. @qopqopqop 's fix worked for me. Using Jest version 24.9.0

I only encountered this error when our project started adding new components that use hooks and testing-library. I think there may be some friction between Jest, testing-library, and React hooks as these are all new technologies. These projects are still learning how to play nicely with each other. OR, we could be writing really buggy functional components that use hooks improperly. :-)

I still have this issue. I can't exit the test, this make npm test fail for all my app. any clue?

@koooge Can you post an example of what doesn't work for you?

To make the test exit with 0 after all tests pass you have to pass in --watchAll=false
like npm run test -- --watchAll=false

this worked for me

To make this work with Firebase I had to do this:

afterAll(() => {
    firebase.app().delete();
});

I've fixed it using the option:

--forceExit

https://jestjs.io/docs/en/cli#--forceexit

So I ran into this issue as well. It was annoying seeing the A worker process has failed to exit gracefully and has been force exited... warning message when I knew I was handling all of my async calls correctly. I ran my tests with the --detectOpenHandles but nothing showed up. After some research, I discovered that my culprit was Promise.race.

I use a native promise utility library (https://github.com/blend/promise-utils) and wrap some of my external API calls in the timeout utility. This utility in-turn uses the native Promise.race.

I pulled that code out and created a simple test case to confirm my findings.

it('promise.race', async() => {
  await Promise.race([
    new Promise((res) => setTimeout(res, 10000)),
    Promise.resolve('true')
  ])
})

Assuming your test case timeout settings are default, the above test will always give the warning.

Whatever way jest is using to detect open handles under the hood, it is not taking into consideration handles left open intentionally by Promise.race. This use case definitely falls under the false-positive category. I am not sure this false-positive is fixable, but perhaps one of the devs has an ingenious solution to this.

For now, I am sticking with --forceExit like everyone else.

Edit:
Just found this, seems like it is indeed a deeper nodejs/v8 issue https://github.com/nodejs/node/issues/24321

For anyone else coming here from Firestore tests, this works for me:

afterAll(async () => {
  // Shut down Firestore, otherwise jest doesn't exit cleanly
  await firestoreInstance.terminate()
});

I'm still having the same problem using Apollo & Jest. Unfortunately, even though the option --detectOpenHandles eventually exits, it still makes the process pend for another few seconds (and in contradiction to its name: it doesn't provide information about which handles are still open!).

Using --forceExit does the job but annoyingly prints:

Force exiting Jest: Have you considered using --detectOpenHandles to detect async operations that kept running after > all tests finished?

A workaround I found (and this is by no means a solution!) is adding a teardown to jest.config.js:

globalTeardown: '<rootDir>/__tests__/teardown.js',

and in teardown.js use process.exit:

module.exports = async function () {
    console.log('done!');
    process.exit(0);
}

I also have this problem. How can I fix it? I have set forceExit: true. --forceExit --detectOpenHandles --maxWorkers=10 does not work.

https://github.com/atom-ide-community/atom-ide-base/pull/33

Edit: the issue somewhere else. It is in the test-runner that I am using...

@alusicode
This one did not work for me npm test --watchAll=false
But it worked by adding --watchAll=false in package.json file. 👍

Like

"test": "react-scripts test a jest --ci --reporters=default --reporters=jest-junit --watchAll=false"

Official docs: https://jestjs.io/docs/en/cli.html#--watchall

Not using firebase but I had the same issue on my workflow scripts. using jest without parameters said the some of my scripts didnt shutdown gracefully and I should use --runInBand --detectOpenHandles . That would fix the problem for all of my tests except one ( btw --detectOpenHandles didnt show me the tests that had issues) .
So I started checking all tests one by one. I found out that for 2 tests I forgot to use await when I was calling an async function.
After adding await it was fixed. Although I dont think its normal that --detectOpenHandles doesnt print the issues.

Was this page helpful?
0 / 5 - 0 ratings