Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

window.setImmediate has issues when used with jsdom environment. #11511

Closed
StringEpsilon opened this issue Jun 2, 2021 · 11 comments
Closed

window.setImmediate has issues when used with jsdom environment. #11511

StringEpsilon opened this issue Jun 2, 2021 · 11 comments

Comments

@StringEpsilon
Copy link
Contributor

🐛 Bug Report

When using window.setImmediate() within jest (either as part of the test, or within the tested unit) using the jsdom testEnvironment, an unexpected exception is thrown:

TypeError: setImmediate is not defined

Or, when using the legacy fakeTimers (jest.useFakeTimers("legacy"))

TypeError: this._timerAPIs.setImmediate is not a function

To Reproduce

I made a reproduction repository here: https://github.com/StringEpsilon/jest_jsdom_setimmediate_bug

Clone it, npm install, npm test.

The setup runs 3 tests in both JSDOM and node environments. For the node environment, 1 out of 3 test fails as expected, for the missing DOM in mounting a component. The JSDOM environment run fails all 3 tests.

Expected behavior

window.setImmediate() should work within the jsdom jest environment without throwing an exception.

Link to repl or repo (highly encouraged)

https://github.com/StringEpsilon/jest_jsdom_setimmediate_bug

envinfo

  System:
    OS: Windows 10 10.0.19042
    CPU: (16) x64 AMD Ryzen 7 5800X 8-Core Processor
  Binaries:
    Node: 14.15.3 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 7.6.3 - C:\Program Files\nodejs\npm.CMD
@Smrtnyk
Copy link

Smrtnyk commented Jun 2, 2021

you are not using jsdom as environment in your repro
you are using jest 27 which by default runs tests in node environment

Please read the documentation and blog post for jest 27 https://jestjs.io/blog

@StringEpsilon
Copy link
Contributor Author

StringEpsilon commented Jun 2, 2021

The jest.config.js does not specify an environment, because I set those manually in the npm test command. The entry in the config file would be superfluous for a reproduction.

"test": "jest --testEnvironment node; jest --testEnvironment jsdom"

As to demonstrate that 1/3 tests fail with the node environment and 3/3 test fails with the jsdom environment.

@Smrtnyk
Copy link

Smrtnyk commented Jun 2, 2021

Hm you are right, I checked my tests which I have around 3.3k and some of them rely on setImmediate to resolve the Promise queue for some tests
What I did after migration to jest 27 is that I imported setImmediate

import { setImmediate } from "timers";

Jest bumped jsdom version so not sure if it is something from jsdom or jest mocks the setImmediate now

@SimenB
Copy link
Member

SimenB commented Jun 3, 2021

It's not a global in the browsers, so we removed it from the JSDOM env: #11222

@SimenB SimenB closed this as completed Jun 3, 2021
@julienw
Copy link

julienw commented Jun 7, 2021

Hey,
Let me start by saying I'm globally in favor of the change.

Then I'm not 100% sure of the reason, but we've seen problems using fake-indexeddb because of this change, when using fake timers.

With the legacy fake timers, we get the error:

    TypeError: this._timerAPIs.setImmediate is not a function

I believe this is from this line:
https://github.com/facebook/jest/blob/f628b4564dfafb6ed218f9119141b1521024e79d/packages/jest-fake-timers/src/legacyFakeTimers.ts#L444

where the legacy fake timers call setImmediate directly. It looks like that with the legacy timers, setImmediate is still present in the global object?

With the modern fake timers, I get a timeout instead. I believe that in that case Fake-indexeddb uses the polyfill of setImmediate, and this results in using setTimeout which doesn't resolve automatically when the fake setImmediate does.

My guess is that this may bring problems in other codebases where polyfills for setImmediate uses setTimeout.

By chance, is there an easy way to opt-in to adding it in our environment? Or just have a way to reinstante the node implementation of setImmediate? For now I added global.setImmediate = process.nextTick which goes a long way.

Thanks!

@SimenB
Copy link
Member

SimenB commented Jun 7, 2021

That's a bug in legacy timers, it should check for presence in global before adding an immediate. Mind opening up a separate bug report?

@julienw
Copy link

julienw commented Jun 7, 2021

I filed #11539.
But is there a way to have node's setImmediate in jsdom's global otherwise? This would help some migration.
Thanks!

@SimenB
Copy link
Member

SimenB commented Jun 7, 2021

You'll need to polyfill it yourself or use a custom environment extending our JSDOM one

@julienw
Copy link

julienw commented Jun 7, 2021

For now I added global.setImmediate = process.nextTick which goes a long way.

Of course this doesn't work with @testing-library/dom.

You'll need to polyfill it yourself or use a custom environment extending our JSDOM one

I see, I'll try something.

Thanks for the answers!

@julienw
Copy link

julienw commented Jun 7, 2021

FYI I filed dumbmatter/fakeIndexedDB#64 in fakeIndexedDB repository.

@github-actions
Copy link

github-actions bot commented Jul 8, 2021

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants