So you’ve written your tests in Jest and now you’re either getting warning messages in your console, perhaps about event emitters or memory leaks, or maybe you’ve pushed up to a remote repository like BitBucket and now your Pipelines are failing and you can’t quite figure out why.

I’ve had this issue a few times while working with Jest, there are several things that could be causing it but as a rule of thumb, at least in my case, it was always either to do with timers or event emitters. Below are a few tips on troubleshooting these issues with Jest, and a couple of potential solutions.

Troubleshooting Tips

Firstly it’s important to note that you can run tests one file at a time by appending the file name to the end of your test command. This is handy if you’re not sure which test file the issues is in.

jest example.spec.js

Secondly you can make use of the .skip or .only methods in Jest to only run specific tests. If you have a lot of tests you might find it easier to comment half the file and narrow down where the issue is.

it('should not run this test', () => {
  expect(true).toBe(false)
})

it.only('should run this test', () => {
  expect(true).toBe(true)
})

Next there are some Jest flags that might help you narrow things down.

  • --detectOpenHandles has never helpe me personally but you can try it (be aware this implies --runInBand which will run all of your tests in series rather than parallel)
  • --logHeapUsage will tell you how much memory each test file is using which might give you some clues.
jest example.spec.js --logHeapUsage

Finally you could try the --detectLeaks flag, note that this may require you to install the weak-napi package in your project:

node --expose-gc ./node_modules/.bin/jest --coverage --detectLeaks

Potential Solutions

There are a few common issues that I see crop up again and again:

Ensure everything is properly mocked

If you’re using a package, for example the cron package, and you don’t mock it with:

jest.mock('cron')

You may find that it is creating timers or event listeners in the background which could be the source of your issue. Not all packages need to be mocked in tests but packages like this definitely should be.

Timers

If you have any code that calls setTimeout() or setInterval() then these need to be cleared before your tests finish, otherwise your tests will not exit properly.

jest.clearAllTimers()

You could put this in an afterEach or afterAll, I generally put it in my setup.js file so that it automatically applies to everything however what is best will depend on your setup.

It is also worth noting that it’s usually better to use fake timers in Jest so that you can advance time by an arbitrary amount:

jest.useFakeTimers() // tell jest to use fake timers
jest.advanceTimersByTime(5000) // advance time 5000ms
jest.setSystemTime(1700000000000) // set time to a specific epoch (in ms)

Event listeners

In JavaScript event listeners are usually added with the .on() method, generally this would only be an issue if you have an infinite loop somewhere in your code but there are a couple of other scenarios where is could be an issue:

If you have a method that adds an event listener, and you call it multiple times, you must remember to detach the old event listener or you will be adding multiple/duplicate event listeners.

If your tests are not properly isolated i.e. you create a single wrapper or instance of an application and then run 100 tests against it, all of which add one or more event listeners when you call some sort of init function.

In either of these scenarios the solution is to either make sure you remove the old listeners when you’re done with them or not to add more listeners than you need in the first place, for example by isolating each it statement in your tests so they have their own instance of the app to work with.

Further Reading

It’s worth having a quick look through the Jest docs, specifically the CLI options and the methods available on the Jest object itself:

These articles may also help:


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.