Skip to content

runWithRealTimers's setImmediate polyfill will still use the fake setTimeout #1767

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

Open
edkimmel opened this issue May 9, 2025 · 2 comments

Comments

@edkimmel
Copy link

edkimmel commented May 9, 2025

Describe the bug

This happens for both the setimmediate node_module and RNTL's polyfill.

The root cause for both flows is the same - we are not capturing the underlying timer functions while the timers are real. When we actually call setImmediate (Like in the automatic cleanup), it's back to referencing fake timers.

For the setimmediate module case, you can see that registerImmediate doesn't capture the global functions it will use, it just pulls from global state on demand.

For the polyfill you can see the same issue, it will end up pulling the fake setTimeout when called later on, when fake timers are re-applied.

A potential fix for this is to only use RNTL's polyfill, and to capture setTimeout while inside the bind function.

function bindTimeFunctions() {
  // We need to capture setTimeout now, while jest timers are known to be real
  const setTimeout = globalObj.setTimeout
  function setImmediatePolyfill(fn) {
    return setTimeout(fn, 0);
  }
  return {
    clearTimeoutFn: globalObj.clearTimeout,
    setImmediateFn: setImmediatePolyfill,
    setTimeoutFn: setTimeout
  };
}

Expected behavior

I would expect the functions returned by runWithRealTimers to always use real timers, regardless of the future state.

Steps to Reproduce

Enable testEnvironment: 'jsdom' in jest.config.js
Use fake timers and the RNTL auto cleanup. The test will time out waiting for flushMicroTasks's setImmediate, which is using fake timers accidentally.

Screenshots

Versions

13.2 & 14.0 alpha

@mdjastrzebski
Copy link
Member

Interesting, what would be a minimal test that showcases the described behavior?

@edkimmel
Copy link
Author

edkimmel commented May 10, 2025

#1768

@mdjastrzebski I figured out the simple answer - testEnvironment: jsdom nulls out setImmediate to act as a browser environment, which causes RNTL's polyfill to be used. The polyfill is subject to the bug above, causing the issue.

The PR above now shows it failing when using jsdom. Removing that line from jest.config.js passes the test once more.

Now that I know it's because of jsdom, this is now a duplicate of this issue from a few years ago.

@edkimmel edkimmel changed the title runWithRealTimers's setImmediate is still using fake timers runWithRealTimers's setImmediate polyfill will still use the fake setTimeout May 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants