-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Use only public api for ReactDOMEventListener-test.js #11327
Conversation
document.createElement('div'), | ||
); | ||
|
||
ReactDOM.findDOMNode(component).appendChild(otherNode); |
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 not sure about this first test, it seems to have lost its initial purpose.
); | ||
|
||
ReactDOM.findDOMNode(component).appendChild(otherNode); | ||
ReactTestUtils.SimulateNative.mouseOver(otherNode); |
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 these purposes, I'd like to treat SimulateNative
(and all the ReactTestUtils really as an internal API. The reason for that is that they also reach into internals indirectly. They actually bypass some of the implementation details that would make this example not work with normal React.
In normal React this wouldn't work because the container div is not in the document and therefore mouse moves would never be dispatched on top of it. React can't pick it up because it uses event listeners on the document to do it.
Instead, we should insert the container div into the document, dispatch a native event and then remove the div from the document. Like this:
https://github.com/facebook/react/blob/master/packages/react-dom/src/__tests__/ReactDOMInput-test.js#L55-L59
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.
Hey! I did the requested changes, could you take a look at it?
I'm still not sure if the first test is on spot because before it tested two unrelated components and now they have a parent-child relationship.
Also while we are at this file, I'm not sure how to rewrite should not get confused by disappearing elements
.. I think I understand the thinking behind it but I'm not sure if it's possible to accomplish the same result without mocking handleTopLevel
. I'd have to unmount a component in the middle of the event chain, which seems impossible.
Thanks!
|
||
var container = document.createElement('div'); | ||
var stub = ReactDOM.render(<div onMouseOver={mock} />, container); | ||
var node = ReactDOM.findDOMNode(stub); |
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.
There's no "stubs" anymore, you can remove these findDOMNode()
calls. Return value of ReactDOM.render(<div />)
is the node itself.
var container = document.createElement('div'); | ||
var stub = ReactDOM.render(<div onMouseOver={mock} />, container); | ||
var node = ReactDOM.findDOMNode(stub); | ||
var otherComponent = document.createElement('h1'); |
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.
Let's not call nodes "components". I understand this naming already existed but let's keep it clear in new code. We call DOM nodes "nodes" in newer code (or "containers" when we render into them). So otherNode
was a good naming.
var stub = ReactDOM.render(<div onMouseOver={mock} />, container); | ||
var node = ReactDOM.findDOMNode(stub); | ||
var otherComponent = document.createElement('h1'); | ||
node.appendChild(otherComponent); |
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.
Why is it appended as a child to node
? I don't see it in the original test. My impression (based on the test name) is that the test specifically wants to test it still works if the otherComponent
is outside the React tree. Whereas this is putting it inside.
otherComponent.dispatchEvent(nativeEvent); | ||
|
||
expect(mock).toBeCalled(); | ||
document.body.removeChild(container); |
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 the right way to write this test would be something like:
var mock = jest.fn();
var container = document.createElement('div');
var node = ReactDOM.render(<div onMouseEnter={mock} />, container);
var otherNode = document.createElement('h1');
document.body.appendChild(container);
document.body.appendChild(otherNode);
var nativeEvent = document.createEvent('MouseEvent');
nativeEvent.initMouseEvent('mouseout', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, node);
otherNode.dispatchEvent(nativeEvent);
expect(mock).toBeCalled();
This way we verify that if an event originates outside of React tree (on otherNode
) it still fires an event inside a React tree.
I had to use a different event but that doesn't matter for this test.
}); | ||
var nativeEvent = document.createEvent('Event'); | ||
nativeEvent.initEvent('mouseout', true, true); | ||
ReactDOM.findDOMNode(childControl).dispatchEvent(nativeEvent); |
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.
No findDOMNode
please.
var parentContainer = document.createElement('div'); | ||
var parentControl = <div>Parent</div>; | ||
var parentControl = <div onMouseOut={onMouseOut}>div</div>; | ||
childControl = ReactDOM.render(childControl, childContainer); | ||
parentControl = ReactDOM.render(parentControl, parentContainer); | ||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer); |
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.
Here, too, we can remove all findDOMNode
s.
@@ -90,22 +95,25 @@ describe('ReactDOMEventListener', () => { | |||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer); |
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 re: findDOMNode.
return <div><div id="outer">{inner}</div></div>; | ||
} | ||
} | ||
|
||
var instance = ReactTestUtils.renderIntoDocument(<Wrapper />); | ||
ReactTestUtils.SimulateNative.mouseOut(instance.getInner()); |
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.
Let's rewrite this one not to use SimulateNative
either. Can we?
Thanks for the feedback! |
document.body.appendChild(container); | ||
document.body.appendChild(otherNode); | ||
|
||
var nativeEvent = document.createEvent('MouseEvent'); |
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 saw another PR using new MouseEvent(type, args)
, could you check if that one's going to be shorter?
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 it seems
new MouseEvent('mouseout', {
bubbles: true,
cancelable: true,
relatedTarget: node,
})
works just fine.
I think it just wants to test that if you
React batches updates occurring inside the same browser event. Means it applies all changes when it exists the top-level browser event handler (instead of when it exits component handler). This test verifies this behavior is true even if two components live in separate React trees (but in the same document). In other words it wants to verify that if you do var mock = jest.fn(); and then, inside child (in a separate root) event handler: ReactDOM.render(<div>1</div>, childContainer);
mock(childNode.textContent); and inside parent (in a separate root) event handler: ReactDOM.render(<div>2</div>, childContainer);
mock(childNode.textContent); Both calls to |
Looks like a test is still failing. Would you like to continue working on this? |
Yeah there's just one missing. |
Thanks, sounds good! |
So, I think I was able to reproduce the same test case but I couldn't find the code that introduced that fix you mentioned, so confirmation is still necessary. The blame for that lines seem to be sort of detached from the git tree.. |
There was no need to extract React elements into separate variables.
I could not get it to fail on master so it was probably testing something specific to Stack implementation details. It was also already broken because it didn't look at the right argument and never actually called `unmountComponentAtNode`. Instead I replaced it with original repro case from #1105 which is when it was introduced.
<div>{topLevelTarget === childNode ? '1' : '2'}</div>, | ||
childContainer, | ||
); | ||
// Since we're batching, neither update should yet have gone through. |
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.
Comments like this are valuable because they're not obvious.
This looks great! Thanks. I made a few small tweaks. |
* Use only public api for ReactDOMEventListener-test.js * Use less confusing naming There was no need to extract React elements into separate variables. * Replace the "disappearance" test I could not get it to fail on master so it was probably testing something specific to Stack implementation details. It was also already broken because it didn't look at the right argument and never actually called `unmountComponentAtNode`. Instead I replaced it with original repro case from facebook#1105 which is when it was introduced. * Tweak naming and add comments * Missed this one
Related to #11299 – Express more tests via public API
Hey! After a couple hours fighting with this one I think I got the idea..
Could you guys check if I'm in the right direction?
BTW, I lost quite some time until I realized this line: https://github.com/facebook/react/blob/master/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js#L32 was messing up with
ReactTestUtils.SimulateNative
... Funny, that's probably the reason why we are using just the public api 😅