-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Shallow renderer and test utils bundles #9426
Conversation
d98cfee
to
fb05fc9
Compare
enumerable: false, | ||
writable: false, | ||
value: owner, | ||
}); |
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.
Related past discussion #6355
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.
Can you verify with @sebmarkbage he has no concerns here?
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.
Seb and I chatted about this idea in person. He didn't seem to, but I'll let him comment here (or I can follow up with him in person on Monday). Sure!
a5b7aff
to
b8c35d8
Compare
Adding a few more folks who may be interested in looking over this change |
|
||
if (process.env.NODE_ENV === 'production') { | ||
throw Error('shallow renderer is not available in production mode.'); | ||
} else { |
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.
Should we also throw for the main test renderer entry point then?
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.
Or should we create prod versions of all of them? I don't see benefit but somebody might come up with a use case. Maybe just worth keeping in mind.
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.
Or should we create prod versions of all of them?
I don't see the value of this, and it would cause problems with __DEV__
only things like the non-enumerable _owner
attribute.
I'll throw in the main test renderer too, sure.
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.
scripts/rollup/results.json
Outdated
"gzip": 55887 | ||
}, | ||
"react-test-utils.development.js (NODE_DEV)": { | ||
"size": 510240, |
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.
I think this file was deleted so the stat is probably not needed?
enumerable: false, | ||
writable: false, | ||
value: owner, | ||
}); |
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.
Can you verify with @sebmarkbage he has no concerns here?
const tree = this._renderer.toTree(); | ||
if (tree && tree.rendered) { | ||
// If we created a context-wrapper then skip over it. | ||
const element = tree.type.childContextTypes |
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 seems fragile. What if it isn't our context but the root element just happens to be a context provider?
To be honest I'm not a fan of second undocumented context
argument. Our other APIs don't take it. I think it's remaining from the time context was owner-based and we might as well deprecate it and tell people to use their own context providers explicitly. But it's probably annoying to do in this PR.
Let's just be stricter with checking here.
|
||
// Convert the rendered output to a ReactElement. | ||
// This supports .toEqual() comparison for test elements. | ||
return React.createElement( |
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.
Would this re-trigger any validation? Would people see duplicate messages?
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 would only re-trigger if the ReactElement
returned from the top-level render was a class component with propTypes
. In that case, it still wouldn't show a duplicate message because checkPropTypes
tracks loggedTypeFailures
and avoids re-logging duplicates.
Do you think this is reasonable? Should I look for a way of bypassing checkPropTypes
for this case (or some other approach)?
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.
What about the key warning?
It’s probably fine, just making sure you’re aware of this.
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.
Key warning will only log once as well.
Yup, much appreciated for the double check. 😄
|
||
getRenderOutput() { | ||
if (this._renderer) { | ||
const tree = this._renderer.toTree(); |
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 will likely make all shallow tests slower. Would be good to measure it on some mid size codebase to check the impact. It might be better to add some way of bailing out if it's too bad.
@@ -12,23 +12,27 @@ | |||
'use strict'; | |||
|
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.
While we're at it can we move src/test
to a more appropriate place (considering the package structure)?
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.
Done!
class SomeComponent extends React.Component { | ||
render() { | ||
// Shallow renderer only implemented for Fiber in 16+ | ||
if (ReactDOMFeatureFlags.useFiber) { |
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.
I'm a bit confused by this comment. Can we branch on require instead? Otherwise it looks like we stopped testing shallow renderer in Stack at all. However the Stack version is what we're currently running in www.
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.
Otherwise it looks like we stopped testing shallow renderer in Stack at all.
This new shallow renderer is fiber only. Seemed like too much effort to create a new one that supports stack and works with our new bundles- just to throw it away. (I mentioned this in the description but maybe it wasn't prominent enough.)
I'm not sure how to address www yet. I'll give it some more thought. 😄
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.
Oh. I didn't realize we deleted the Stack based one. Our usual strategy is to keep both until we’ve migrated everything that uses the old one (e.g. www). This lets us revert to using the old one if the new one has issues. Otherwise once this is merged, we have no way but to fix forward. Which might be fine, but it’s blocking any future syncs, and I don’t know if this will pass www tests or not.
Usually we keep both, and let the tests pick the right one based on the flag.
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.
Yeah, totally understood- and I'm glad you bought it up. I'll figure out a strategy for www tests with stack once the fiber bundles and renderer is solid. 😁
I am also concerned that running |
Great point Dan. I just realized something silly anyway 😐 The new renderer actually causes render to be called on the full tree because of how the reconciler works. I need to think about this a bit more. I'll also add a test to verify that the shallow renderer is...shallow. This is embarrassing. 😅 |
Yea, this is what I meant by the "bailout" in the comment above. The original PR by @lelandrichardson contained this logic in a more generic way (it allowed "redirecting" types) and I think @sebmarkbage had a strategy for using this for shallow renderer in #8931 (comment). This way it would only render one level deep. |
Gotcha! Thanks for pointers. 😄 |
bef9f05
to
86bfb52
Compare
Gave this some more thought over the weekend and tried a couple of alternate implementations. One was similar to |
I ran shallow renderer tests in www against the new
I also tried plugging the new renderer into a local copy of Enzyme but didn't spend much time on it once I realized there was some internal coupling (eg In the meanwhile I've reached out to Leland and made him aware of some of the issues I noticed. I think he's going to take a look at this branch and we'll chat some more about it. |
Files now import directly from prop-types/checkPropTypes
* Moved test-utils into react-dom package * Added test-utils to package.json 'files' list * Added ReactTestUtilsFBEntry module (though it doesn't really do anything at the moment) * Replaced ReactDOM references with react-dom to avoid duplicating code
…ific entry point. Throw explicit error if imported in prod mode
All 617 Enzyme unit tests pass for react/react-dom 15 + the new shallow renderer if I make the following patch: diff --git a/src/ShallowWrapper.js b/src/ShallowWrapper.js
index bd23106..ade4e73 100644
--- a/src/ShallowWrapper.js
+++ b/src/ShallowWrapper.js
@@ -194,7 +194,11 @@ class ShallowWrapper {
if (this.root !== this) {
throw new Error('ShallowWrapper::instance() can only be called on the root');
}
- return this.renderer._instance ? this.renderer._instance._instance : null;
+ const instance = this.renderer._instance;
+
+ return instance && instance._instance
+ ? instance._instance
+ : instance;
}
/** The above patch accounts for the fact that we no longer auto-wrap functional components in a class component. Enzyme isn't compatible with React 16 yet because there are a lot of hooks into internals. But this improves my confidence about the new shallow renderer and its backwards compatibility (at least from an external POV). |
Don't require subclass constructors to pass this along to super
To be clear I don't think it's as important that Enzyme's own tests pass (which may rely on internals too much) since it's bound for major anyway. But we should test it on large projects using shallow rendering (via Enzyme or not). |
Uh, right. But Enzyme's own tests seem like a pretty useful metric given their volume. If the new renderer passes all of their tests- that's a good sign, no? I'm having trouble testing it on projects using shallow renderer because none of them have updated to be React 16 compatible yet. |
What do you think ShallowRender has a new API like It would be nice if it is accomplished without depending on React internals. |
Yeah, I had to patch AirBnb has plans to rewrite Enzyme internals for the next release though. The idea is for libraries like React (and similar ones- Preact, Inferno, etc) to provide an abstraction layer / adapter that Enzyme consumes rather than reaching into internals. The Enzyme team can then create adapters on their side (eg one for each major version of React) so their core can be cleaned up. (This file has since been deleted, or maybe moved, but I think it explains the general idea.) That's a bit orthogonal to this PR though probably. At the moment, I don't think they have any plans of actually using this new shallow renderer. It's for non-Enzyme users (including Facebook's non-Enzyme tests). |
By the way, Dan- thanks for the unblock approval. I'm going to spend a little more time walking through the 30 failing tests in www and writing down the reasons why they're failing (patching things up if possible) to make our later sync easier. I hope to merge this PR sometime tomorrow. |
… test vars to const/let
Sounds great! |
All www tests pass now! Added a few more tests for edge-cases I found while running through www tests. Soon as Circle gives it a green check, I'll merge. |
For posterity (or future-me) here's the list of mods I made in www while testing:
I'll submit a WIP diff for the above changes internally as well for when we eventually sync a newer alpha to www. |
Great work! 🎉 |
Thanks so much for the helpful info you provided @koba04 ! |
Great work! |
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.
Whoops, meant to add a single line comment
|
||
if (process.env.NODE_ENV === 'production') { | ||
throw Error('shallow renderer is not available in production mode.'); | ||
} else { |
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.
I added prod builds in 16.1. You can try |
Hmm. Upgraded to |
This code doesn't exist in it. https://unpkg.com/[email protected]/shallow.js If you still see the issue you have not upgraded. Or forgot to update some packages. |
Ah you're right, yes I updated |
Shallow renderer and test utils bundles Adds new bundles introduced with React 15.5 release to master (and 16 alpha) react-dom/test-utils: This new bundle contains what used to be react-addons-test-utils. This bundle shares things from react-dom rather than duplicates them. A temporary createRenderer method has been left behind as a way to access the new shallow renderer. This is for the ReactNative release cycle only and should be going away before the final release. react-test-renderer/shallow: This new shallow renderer is almost entirely stand-alone (in that it doesn't use the React reconciler or scheduler). The only touch points are ReactElement and prop/context validation. This renderer is stack and fiber compatible.
Adds new bundles introduced with React 15.5 release to master (and 16 alpha):
react-dom/test-utils
This new bundle contains what used to be
react-addons-test-utils
. This bundle shares things fromreact-dom
rather than duplicates them.A temporary
createRenderer
method has been left behind as a way to access the new shallow renderer. This is for the ReactNative release cycle only and should be going away before the final release.react-test-renderer/shallow
This new shallow renderer is almost entirely stand-alone (in that it doesn't use the React reconciler or scheduler). The only touch points are
ReactElement
and prop/context validation. This renderer is stack and fiber compatible.PS I used
__SECRET_INTERNALS
please don't fire me 😛