,
+ grandParentContainer,
);
+ parentNode.appendChild(childContainer);
+ grandParentNode.appendChild(parentContainer);
+
+ document.body.appendChild(grandParentContainer);
+
+ var nativeEvent = document.createEvent('Event');
+ nativeEvent.initEvent('mouseout', true, true);
+ childNode.dispatchEvent(nativeEvent);
+
+ expect(mouseOut).toBeCalled();
+ expect(mouseOut.mock.calls.length).toBe(3);
+ expect(mouseOut.mock.calls[0][0]).toEqual(childNode);
+ expect(mouseOut.mock.calls[1][0]).toEqual(parentNode);
+ expect(mouseOut.mock.calls[2][0]).toEqual(grandParentNode);
+
+ document.body.removeChild(grandParentContainer);
});
+ // Regression test for https://github.com/facebook/react/issues/1105
it('should not get confused by disappearing elements', () => {
- var childContainer = document.createElement('div');
- var childControl =
Child
;
- var parentContainer = document.createElement('div');
- var parentControl =
Parent
;
- childControl = ReactDOM.render(childControl, childContainer);
- parentControl = ReactDOM.render(parentControl, parentContainer);
- ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
-
- // ReactBrowserEventEmitter.handleTopLevel might remove the
- // target from the DOM. Here, we have handleTopLevel remove the
- // node when the first event handlers are called; we'll still
- // expect to receive a second call for the parent control.
- var childNode = ReactDOM.findDOMNode(childControl);
- handleTopLevel.mockImplementation(function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent,
- ) {
- if (topLevelTarget === childNode) {
- ReactDOM.unmountComponentAtNode(childContainer);
+ var container = document.createElement('div');
+ document.body.appendChild(container);
+ class MyComponent extends React.Component {
+ state = {clicked: false};
+ handleClick = () => {
+ this.setState({clicked: true});
+ };
+ componentDidMount() {
+ expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild);
}
- });
-
- var callback = ReactDOMEventListener.dispatchEvent.bind(null, 'test');
- callback({
- target: childNode,
- });
-
- var calls = handleTopLevel.mock.calls;
- expect(calls.length).toBe(2);
- expect(calls[0][EVENT_TARGET_PARAM]).toBe(
- ReactDOMComponentTree.getInstanceFromNode(childNode),
- );
- expect(calls[1][EVENT_TARGET_PARAM]).toBe(
- ReactDOMComponentTree.getInstanceFromNode(parentControl),
+ componentDidUpdate() {
+ expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild);
+ }
+ render() {
+ if (this.state.clicked) {
+ return clicked!;
+ } else {
+ return ;
+ }
+ }
+ }
+ ReactDOM.render(, container);
+ container.firstChild.dispatchEvent(
+ new MouseEvent('click', {
+ bubbles: true,
+ }),
);
+ expect(container.firstChild.textContent).toBe('clicked!');
+ document.body.removeChild(container);
});
it('should batch between handlers from different roots', () => {
+ var mock = jest.fn();
+
var childContainer = document.createElement('div');
+ var handleChildMouseOut = () => {
+ ReactDOM.render(
1
, childContainer);
+ mock(childNode.textContent);
+ };
+
var parentContainer = document.createElement('div');
- var childControl = ReactDOM.render(
Child
, childContainer);
- var parentControl = ReactDOM.render(
Parent
, parentContainer);
- ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
-
- // Suppose an event handler in each root enqueues an update to the
- // childControl element -- the two updates should get batched together.
- var childNode = ReactDOM.findDOMNode(childControl);
- handleTopLevel.mockImplementation(function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent,
- ) {
- ReactDOM.render(
-
{topLevelTarget === childNode ? '1' : '2'}
,
- childContainer,
- );
- // Since we're batching, neither update should yet have gone through.
- expect(childNode.textContent).toBe('Child');
- });
-
- var callback = ReactDOMEventListener.dispatchEvent.bind(
- ReactDOMEventListener,
- 'test',
- );
- callback({
- target: childNode,
- });
+ var handleParentMouseOut = () => {
+ ReactDOM.render(
2
, childContainer);
+ mock(childNode.textContent);
+ };
- var calls = handleTopLevel.mock.calls;
- expect(calls.length).toBe(2);
+ var childNode = ReactDOM.render(
+
,
+ parentContainer,
+ );
+ parentNode.appendChild(childContainer);
+ document.body.appendChild(parentContainer);
+
+ var nativeEvent = document.createEvent('Event');
+ nativeEvent.initEvent('mouseout', true, true);
+ childNode.dispatchEvent(nativeEvent);
+
+ // Child and parent should both call from event handlers.
+ expect(mock.mock.calls.length).toBe(2);
+ // The first call schedules a render of '1' into the 'Child'.
+ // However, we're batching so it isn't flushed yet.
+ expect(mock.mock.calls[0][0]).toBe('Child');
+ // The first call schedules a render of '2' into the 'Child'.
+ // We're still batching so it isn't flushed yet either.
+ expect(mock.mock.calls[1][0]).toBe('Child');
+ // By the time we leave the handler, the second update is flushed.
expect(childNode.textContent).toBe('2');
+ document.body.removeChild(parentContainer);
});
});
it('should not fire duplicate events for a React DOM tree', () => {
+ var mouseOut = jest.fn();
+ var onMouseOut = event => mouseOut(event.target);
+
class Wrapper extends React.Component {
getInner = () => {
return this.refs.inner;
@@ -194,21 +193,22 @@ describe('ReactDOMEventListener', () => {
render() {
var inner =