-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
scheduleFn is calling NormalPriority as a function rather than cb #736
Comments
Hi @lerouxb, thanks for sending this one. |
The code is finding Scheduler on globalObj. I guess it isn't guaranteed to exist on global || window in every testing setup. |
It also tries to require it: |
The code seems to be treating the existence of Scheduler as optional. I think it should consistently do it in all the lines. And if it doesn't exist, then use the single parameter form of the function. |
And we probably need to require the scheduler as an optional peer dependency. Otherwise it might not be available depending on the dependency tree and package manager. |
@eps1lon Isn't having |
Is scheduler a peer of react-dom or react? Either way, implicit dependencies are a problem. Definitely for newer package managers such as pnpm and yarn 2. |
|
Btw, I just tried npm install scheduler and that's not enough to fix this. |
The line
Is in the same try {} catch {} as the existing And it looks like that's exactly what's happening: the timers import is throwing and the catch is executing. (nodeRequire is undefined) |
I wouldn't have expected that because the package manager still doesn't know that testing-library requires it. |
So I dug into this further, and here's what's happening for us:
The bug then happens as follows:
Hope this makes sense |
This is testing through webpack + karma + ChromeHeadless
I agree this is problematic but fwiw, if I add Adding extra globals to window is obviously not a great solution though. |
Thanks @bengillies, that really helpful. |
This sounds right to me. I'm not really an expert on how bundlers are importing things, but it seems to me like
isn't really relevant to the Scheduler as it's being imported and used directly and not polyfilled from node. If that's the case, is it just a case of importing it directly at the top of the file along with |
Well, the problem is that we want the specific |
Thinking about this, I don't really understand what's different between importing
Is it not already implicitly coupled to the version I guess the ideal situation would be for react-dom to expose its scheduler somewhere so that you can hook into it right? I guess that's perhaps not realistic. |
importing at the top of the file if there's no
If you use |
I can't speak to other build systems, particularly as you're mixing ES style Approach 1:
try {
Scheduler = Scheduler || require('scheduler');
} catch(_err) {
isModernScheduleCallbackSupported = false;
} or Approach 2: Add the following line into the catch block that already exists: isModernScheduleCallbackSupported = false; This then ensures that if the call to import Scheduler fails, the rest of the code doesn't assume it succeeded. |
Let's go with approach 2. |
@kentcdodds, @bengillies |
I'm unsure why it is we're unable to require the scheduler if it's there |
Oh wait. I understand. I actually thought about this when I was helping work on this and this:
was the solution I thought would work best. It should be documented. No other changes necessary. This is an edge case and I can't think of a better way to accomplish this. |
Oh, that said I think we should also make sure this doesn't throw an error like it is if someone forgets to do that. So option 2 is probably a good idea as well |
Not actually scheduling a callback with the real scheduler is only sometimes problematic, so we should be ok most of the time. |
@kentcdodds I can document this one and also create the fallback with option 2. |
This seems like a fair approach to me. Thanks for your help. |
I'm not following why a scheduled callback flushes microtasks. Can we go back a bit and explain what we're trying to accomplish with If we know what problem we're trying to solve we can consult with React core members. I don't think this current approach is something they want to be used by 3rd party libraries. Especially because it mixes so many (old, new, non-standard) module systems. |
The biggest problem is when using fake timers. It's really hard to explain, and I'm feeling really tired right now so I don't think I can properly explain it. but if we don't do things this way then we could end up with a situation in some cases where a scheduled to call back hangs preventing future callbacks from being run. I spent two days on this problem. I agree that it's an implementation detail, but this is why libraries like ours exist. So that the users of the library don't have to worry about the intricacies and weirdness that we do. |
But this approach of doing it on our own and not adding tests (in any form) already failed for
Why do we need to? So far react doesn't have any documentation how to use the |
I just ran into what looks like the exact same issue.
This exception happens immediately after the first test case. Apparently, the error happens in the afterEach hook. Relevant code in react.esm.js is: function scheduleCallback(cb) {
var NormalPriority = Scheduler ? Scheduler.NormalPriority || Scheduler.unstable_NormalPriority : null;
var scheduleFn = Scheduler ? Scheduler.scheduleCallback || Scheduler.unstable_scheduleCallback : function (callback) {
return callback(); //<============ exception on this line
};
return isModernScheduleCallbackSupported ? scheduleFn(NormalPriority, cb) : scheduleFn(cb);
} Using break on exceptions to get more info, I get:
→ So this matches perfectly with OP's. By bisecting versions and commits, I can tell that:
By reading the discussion, it seams I am not bringing much new. Confirmation maybe, and another setup that exhibits the same behavior. |
I ran into this issue as well with a very basic test using jest. That test is on GitHub if you want to try locally: Note that to get past the immediate problem I simply did: jest.useFakeTimers(); |
…y#736-fallback-to-callback
This should be published in a few minutes. |
🎉 This issue has been resolved in version 10.4.5 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
Confirming 10.4.5 fixes it here too. |
As of https://github.com/testing-library/react-testing-library/pull/732/files we're seeing:
Looking at that PR it seems to have two sources of truth: isModernScheduleCallbackSupported based on the react version and NormalPriority based on the existence of Scheduler.
isModernScheduleCallbackSupported seems to be true yet Scheduler undefined.
Which causes it to call
scheduleFn(NormalPriority, cb)
rather thanscheduleFn(cb)
. And scheduleFn iscallback => callback()
.The text was updated successfully, but these errors were encountered: