-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
Fix isolateModules not working correctly when module has already been imported #8634
Conversation
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed. If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks! |
isolateModules
not working correctly when module has already been imported
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
Codecov Report
@@ Coverage Diff @@
## master #8634 +/- ##
==========================================
- Coverage 63.4% 63.39% -0.01%
==========================================
Files 274 274
Lines 11342 11341 -1
Branches 2770 2769 -1
==========================================
- Hits 7191 7190 -1
Misses 3534 3534
Partials 617 617
Continue to review full report at Codecov.
|
This only updates behavior with regular modules and not mocked modules. The field name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Cc @rogeliog
From what I understand the use case for this is for whenever you are requiring a module that is mocked, which could be stateful. In some cases that mock might have been declared outside of the test file. For example in a |
packages/jest-runtime/src/index.ts
Outdated
) { | ||
moduleRegistry = this._moduleRegistry; | ||
} else { | ||
if (this._isolatedModuleRegistry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the most part it looks good, but there is one thing that worries me. With this new implementation there is one change in behavior.
Let's say that I have module A which depends in module B. If I do . jest.isolateModules(() => A = require('./A');)
it will now also use a different copy of "B" also_(as well as for the dependencies of B)_ I'm worried that this might not be the what the user expects, and might make it a bit hard to debug issues.
My example of A and B might be easier to understand with A being MyComponent
and B being React
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I've updated the code to not affect dependencies within an isolated module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi!
Thanks for all the work. Sorry, what I meant with my comment was just to express that there would be a change in behavior, I’m not saying that one is right and the other isn’t.
@thymikee @SimenB @willym1 I think it is important define exactly how we want isolateModules
to work before proceeding.
I see a couple of options:
- [Current behavior] When an
isolateModules
block gets executed, only modules that are not in the module registry yet will be isolated. This means that things that have already been required will use the existing “require”. - When an
isolateModules
block gets executed, it isolates every single module that gets required. - When an
isolateModules
block gets executed, only the required only the direct requires get isolated but not their internal dependencies.
Here are thoughts for the each option:
- Rolling out option 2 and 3 will break a lot of existing tests when people upgrade their versions of Jest in ways that might be hard to spot.
- Option 1 still has the problem mentioned in Requiring modules with isolateModules does not work if module has already been required with a non-isolated method e.g: using require. #7863, but for some reason I still I feel this might be the safest behavior for the user(as well as for maintainability). I wonder if we could log a warning when we detect that the user is trying to require a module that is already in the registry. I’m not sure if we can correctly identify those cases without much false positives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that things that have already been required will use the existing “require”.
This is not really documented, isn't it?
I think I lean towards 2, since I'd expect everything inside the callback to get its own copy. This is fairly fresh addition to Jest, so I think there won't be too much cruft around it, especially if we're fixing it for good reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not really documented, isn't it?
Correct, it is not documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaning towards 2 as well. 1 doesn't seem functionally intuitive. If you needed to do multiple tests on a module that requires each one to be a fresh copy, you'd have to individually isolate each module at the start of the test and know beforehand how many copies are needed.
1 and 3 suffers from another issue - since isolateModules
calls aren't hoisted like a regular mock
call would (correct me on this if I'm wrong), there's no guarantee that the internal dependencies of those copies were already previously required. Say you were isolating a module multiple times whose behavior is tied to some stateful internal dependencies. Any copy of the isolated module can indirectly affect the other copies simply by running, which may be problematic if you're trying to do multiple isolated tests. This is just a very specific case btw, I don't see this significantly impacting anyone currently using isolatedModules
in their tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rogeliog In my opinion, option 2 is the most intuitive, and the only behaviour that matches the name of the function. This is exactly what I thought isolatedModules
did when I read the documentation, especially after having just read the documentation for resetModules()
which is right above it, and the explicit mention of the word "sandbox".
This is just a very specific case btw, I don't see this significantly impacting anyone currently using isolatedModules in their tests.
@willym1 I found this issue+PR because this is something I'm currently struggling with. Because of this bug (and because of the lack of async import support: #10428) I've had to use resetModules()
instead.
15d7d5d
to
96a19a1
Compare
Made some revisions addressing @rogeliog's comments:
(also idk what happened here, a bunch of checks just failed on a single test in jest-util. I'm without context but it seems unrelated to my changes) |
Not sure about CI... Master just passed, would you mind rebasing. Maybe circle was weird for a moment? |
96a19a1
to
2174d5a
Compare
c28f8b1
to
c221ac7
Compare
@rogeliog Ready for re-review |
@willym1 could you rebase this, please? |
Any updates here? @willym1 do you need any help? |
No updates since November. What's going on here ? |
Just waiting for a rebase, I think it's good to land? Maybe @rogeliog wants to give it another lookover? |
Hi - sorry this had been sitting for a while and I've forgotten about it. Last time I checked it seems there was still some unresolved implementation discussion. Will hop on this PR again this weekend and see whether there's additional changes needed on my latest update and try to merge if everything's good to go. |
Good to see that you're all still working on this. Thank you for all the good work 👍 |
c221ac7
to
77ecb1a
Compare
a8338b8
to
bf0e82f
Compare
@willym1 seems like this broke a test in |
Yeah there's an issue with how isolated modules deals with mocks. Will investigate some more |
@willym1 were you able to look more into this? |
This PR is stale because it has been open 1 year with no activity. Remove stale label or comment or this will be closed in 30 days. |
I'm unsure if this has been fixed by another PR, but I'll just comment here to prevent bot supremacy. |
I've merged in |
#10963 seems to have addressed the same issue? The test added in this PR doesn;t pass on master however, while the test added in that PR still passes. Not sure if the behaviour here is more correct, tho 😅 ANd regardless, we need to fix the error in the regex tests |
This PR is stale because it has been open 1 year with no activity. Remove stale label or comment or this will be closed in 30 days. |
This PR was closed because it has been stalled for 30 days with no activity. Please open a new PR if the issue is still relevant, linking to this one. |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
This addresses #7863 where any requires inside
isolateModules
callback were retrieving modules from the regular module registry if the module was previously required in a non-isolated scope.It didn't work previously because the logic checked for
this._moduleRegistry.get(modulePath)
FIRST to assign the variable as a regular module, which would always evaluate to true if the module had already been loaded.The fix was to update the associated if block to check that
this._internalModuleRegistry
exists FIRST to assign the variable as an isolated module.Test plan
runtime_require_module_or_mock.test.js
jest-cli
to my local sandbox project and ran additional tests (see below)