prisma: Jest 27 errors with `ReferenceError: setImmediate is not defined`

Problem

While upgrading to 27.0.3 of jest, I have failing integration tests because

 ● Test suite failed to run

    ReferenceError: setImmediate is not defined

      at Parser.destroy (../../../node_modules/@prisma/client/runtime/index.js:25498:7)
      at detachSocket (../../../node_modules/@prisma/client/runtime/index.js:25536:21)
      at Socket.onSocketClose (../../../node_modules/@prisma/client/runtime/index.js:25545:5)

Suggested solution

Because setImmediate is a non-standard API in the first place, and only officially supported by ie10, prisma should remove references to it.

Sorry if this is the wrong report time, I was split between a feature request and a bug.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 1
  • Comments: 34 (4 by maintainers)

Commits related to this issue

Most upvoted comments

I am afraid I don’t see how this would have worked for anyone

global.setImmediate = jest.useRealTimers;

TLDR: What worked for me is

global.setImmediate = global.setImmediate || ((fn, ...args) => global.setTimeout(fn, 0, ...args));

For those interested https://nodejs.dev/learn/understanding-setimmediate

If you are actually using setImmediate in your tests, but your test environment is actually jsdom, the cleanest approach is to simply import the dependency. Just add this at the top:

/**
 * @jest-environment jsdom
 */

import {setImmediate} from 'timers'

I had the same issue after updating to jest v27. For those who could not solve with any of the previous responses (like me). After some research I’ve solved with:

jest.config.js

module.exports = {
  ...
  setupFilesAfterEnv: [
    '<rootDir>/jest.env.js',
  ],
  ...
}

jest.env.js

global.setImmediate = jest.useRealTimers;

When I put

/*
* @jest-environment node
*/

above my import statements it fixed it for me, since it was a dependency that was using setImmediate. It didn’t work when I put it below the statements.

By the way, if using Jest, make sure your env is set to node instead of jsdom because setImmediate doesn’t exist in jsdom as it is Node-only feature

jest.env.js

global.setImmediate = jest.useRealTimers;

If you’re using TypeScript, the following worked for me:

global.setImmediate = jest.useRealTimers as unknown as typeof setImmediate;

For me setting testEnvironment to node (testEnvironment: 'node',) within jest.config.ts solved the problem.

@silvenon is probably right here.

I chose to replace setImmediate(foo) usages with setTimeout(foo, 0), and for our tests it was adequate.

For anyone else getting here from google or whatever, there are lots of changes regarding setImmediate in the jest changelog for 27 https://github.com/facebook/jest/blob/master/CHANGELOG.md

I’m still investigating, but I suspect https://github.com/facebook/jest/pull/11222 might have to do with it.

obviously make sure your test env is set to node. (ours is, and we still get the problem 🤷‍♂️ ). I’ll update this issue when I figure it out.

EDIT: Just an update as to my investigation on this. I never figured it out, I think updating to an even newer jest version than 27.0.3 may have fixed it, but I don’t have access to the codebase where this was a problem anymore. So I won’t be able to investigate this.

Following @tobilg’s solution, setting global.setImmediate = global.setTimeout; worked for me.

@davidmoshal what kind of code are you testing that needs both DOM and Node environment to exist? Maybe you can work around the problem somehow, so if you post the code someone might be able to help.

The way I see it, the fact that Jest 26 supported setImmediate in jsdom was a mistake corrected in Jest 27.

@davidmoshal my theory was that env jsdom supposes you to run client-side only code inside of it and client side code should not use setImmediate as it is a Node.js feature. When I changed my env to node (after accidentally setting it to jsdom) everything started working, when env is jsdom you don’t have setImmediate in the global object. I guess the reasoning behind it is what I wrote above (client side code should not rely on Node.js specific features). But hey, I might be wrong, I was simply debugging why my jest tests were failing (alas the bug was caused by my lack of attention).

note:

this worked for me, and the bug is in react-native-animated. it detects your environment as “node” even when you’re running jsdom tests

global.setImmediate = jest.useRealTimers;

Hi @janpio

Sorry, 27.0.3 of jest

14.17.4

I didn’t realize it was built into node, I’ll have to investigate why jest 27 is breaking that

I didn’t use setimmediate in my code but in the error, it came from node_modules. I fixed this by

install npm i setimmediate @types/setimmediate

in jest.setup.ts import 'setimmediate';

Ref. https://stackoverflow.com/questions/74902478/why-referenceerror-setimmediate-is-not-defined-when-im-not-using-it-at-all

This is still happening.

@TomSssM: that’s a very strange response. I need jsdom because, as stated above, I’m using Playwright (a browser automation framework).

Jest 26 worked fine (as you noticed), but Jest 27 fails, even if you set the test environment to jsdom, and add the relevant dependencies.

It’s curious to me that Jest 26 works (with the default jsdom environment), yet Jest 27 fails when you explicitly set the test environment to jsdom.

I wonder what has changed in the Jest 27 jsdom implementation?

/*
* @jest-environment node
*/

Such a banger workaround

Just an update as to my investigation on this. I never figured it out, I think updating to an even newer jest version than 27.0.3 may have fixed it, but I don’t have access to the codebase where this was a problem anymore. So I won’t be able to investigate this.

@ericwooley @janpio I’ve seen this error as well. Downgrading from Jest 27.x to 26.6.3 solved the problem.

The error that was being thrown was:

    ReferenceError: setImmediate is not defined

      at Parser.destroy (node_modules/@prisma/client/runtime/index.js:27664:7)

And in the generated runtime client, the code that calls setImmediate looks like:

    destroy() {
      clearTimeout(this.timeout);
      this.timeout = null;
      this.unconsume();
      setImmediate((self) => self.close(), this);
    }

Downgrading Jest hid this error, likely due to Jest overriding setImmediate to muck around with timers internally.

Using jest.useFakeTimers() in jest.setup.ts hid the issue, but if we call prisma.$disconnect() to clean up, we see the issue again. Running jest.runAllTimers() in an afterAll callback after we call prisma.$disconnect() did not help either.

This is likely a Jest issue, but not sure if there’s any advice on how to avoid triggering this.