-
Notifications
You must be signed in to change notification settings - Fork 49.1k
Rewrite ReactDOMInput-test depending on internal API (#11299) #11309
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
Conversation
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.
We're trying to test what happens when the browser changes its internal value of a field. Which it can do without invoking the setter.
What you could do is extract the native setter before we can mutate it. E.g. in beforeEach before the requires.
setUntrackedValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
Then later use:
setUntrackedValue.call(node, 'giraffe');
Note the use of .call
.
var nativeEvent = document.createEvent('Event'); | ||
nativeEvent.initEvent('change', true, true); | ||
node.dispatchEvent(nativeEvent); | ||
ReactTestUtils.SimulateNative.change(node, {target: {value: 'giraffe'}}); |
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.
How do we know that this actually does anything at all? I'm not sure this actually tests the behavior we're trying to test. Since this is a no-change test.
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.
Correct me if I'm wrong, but ReactTestUtils.SimulateNative.change
actually needs to have an element listening to an event to be applied. Any change dispatched to this element won't have any consequences (e.g the value will still be the same). So, judging that in this case, where there's no event at all, makes more sense this way.
You can check a similar case 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.
@sebmarkbage Thank you for the hint with setUntrackedValue.call(node, 'giraffe');
!
It's way more flexible too! Working on right now!
Doubt: Will the changes with |
nativeEvent.initEvent('change', true, true); | ||
node.dispatchEvent(nativeEvent); | ||
setUntrackedValue.call(node, 'giraffe'); | ||
ReactTestUtils.SimulateNative.change(node); |
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.
Hm. What happens if you use the native event dispatching like it was before? Does the test still pass? If so, we should ideally use that mechanism instead since it doesn't rely on by-passing the document event listeners.
ReactTestUtils.SimulateNative
is reaching into internals in a way. That's exactly what we'd like to avoid with these changes.
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.
Totally agree, I'm gonna check it out right now and post here the results.
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.
@sebmarkbage Yes, the tests are passing indeed.
Plus, I think using something like the node.dispatchEvent(nativeEvent);
seems to be a very flexible way to obtain the expected results without reaching those internals.
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.
Btw I verified that using SimulateNative
would have still (incorrectly) passed the test if I removed this line. Whereas with native dispatch it is covered (and fails as it should).
// I don't know how to simulate a change event on a text box. | ||
this.a.dispatchEvent(changeEvent); | ||
this.b.focus(); | ||
dispatchEventOnNode(this.a, 'change'); |
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 has lost the focus()
call. It is important. I verified that removing the fix in 84b8bbd (where this test was introduced) fails on master, but doesn't fail here anymore.
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.
@gaearon Wow, I really wasn't aware of that fix. Thank you! 😃
setUntrackedValue(instance.a, 'giraffe'); | ||
|
||
instance.a.dispatchEvent(inputEvent); | ||
setUntrackedValue.call(instance.a, 'giraffe'); |
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.
Same, but for blur().
They are necessary to cover for the fix in facebook#8240.
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 looks good to me now. I verified that reverting the fixes added with those tests also breaks the tests now.
Sweet. Thanks so much. Do you want to help out reviewing other related PRs now that you have some experience with the kind of issues that come up testing these corner cases? |
Yes, I would appreciate to help out! Actually, I'm sure we got time, but we must verify if there's any inactive individual assigned with a test in order to liberate it so more people can come out and help with the issue |
Yeah, I plan to reach out to folks who took other tests within a few days. Need to review existing ones first :-) |
…facebook#11309) * Rewrite tests depending on internal API * Remove focus being called when there was no blur event function before * Remove triggering function and just let ReactTestUtils take care * Use native events * Remove duplicate * Simulate native event when changing value on reentrant * Change wasn't being called * Use Simulate only * Use React event handlers on test * Move commentary * Lint commit * Use native event * Comment native event dispatching * Prettier * add setUntrackedValue * Prettier-all * Use dispatchEvent instead of ReactTestUtils Simulates; * Prettier * Fix lint * Remove useless arg * Wrap event dispatcher into function * Remove deprecated Event * Remove unused change event dispatcher * Fix merge * Prettier * Add missing focus/blur calls They are necessary to cover for the fix in facebook#8240.
Should help on #11299.
I hope these changes may help with the public APIs on the other tests (especially
inputValueTracking-test
).I'm pretty sure it needs more refactoring and I would appreciate if you could help me pointing the most whopping ones.
As @sebmarkbage stated,
ReactTestUtils
should be considered a non-public API, since it reaches into internals in a way.