Skip to content

Commit 62cfb4d

Browse files
enapupeEthan-Arrowood
authored andcommitted
Use only public api for ReactDOMEventListener-test.js (facebook#11327)
* 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
1 parent 36948c8 commit 62cfb4d

File tree

1 file changed

+144
-144
lines changed

1 file changed

+144
-144
lines changed

packages/react-dom/src/__tests__/ReactDOMEventListener-test.js

Lines changed: 144 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -9,206 +9,206 @@
99

1010
'use strict';
1111

12-
var EVENT_TARGET_PARAM = 1;
13-
1412
describe('ReactDOMEventListener', () => {
1513
var React;
1614
var ReactDOM;
17-
var ReactDOMComponentTree;
18-
var ReactDOMEventListener;
19-
var ReactTestUtils;
20-
var handleTopLevel;
2115

2216
beforeEach(() => {
2317
jest.resetModules();
2418
React = require('react');
2519
ReactDOM = require('react-dom');
26-
// TODO: can we express this test with only public API?
27-
ReactDOMComponentTree = require('../client/ReactDOMComponentTree').default;
28-
ReactDOMEventListener = require('../events/ReactDOMEventListener').default;
29-
ReactTestUtils = require('react-dom/test-utils');
30-
31-
handleTopLevel = jest.fn();
32-
ReactDOMEventListener._handleTopLevel = handleTopLevel;
3320
});
3421

3522
it('should dispatch events from outside React tree', () => {
23+
var mock = jest.fn();
24+
25+
var container = document.createElement('div');
26+
var node = ReactDOM.render(<div onMouseEnter={mock} />, container);
3627
var otherNode = document.createElement('h1');
37-
var component = ReactDOM.render(<div />, document.createElement('div'));
38-
expect(handleTopLevel.mock.calls.length).toBe(0);
39-
ReactDOMEventListener.dispatchEvent('topMouseOut', {
40-
type: 'mouseout',
41-
fromElement: otherNode,
42-
target: otherNode,
43-
srcElement: otherNode,
44-
toElement: ReactDOM.findDOMNode(component),
45-
relatedTarget: ReactDOM.findDOMNode(component),
46-
view: window,
47-
path: [otherNode, otherNode],
48-
});
49-
expect(handleTopLevel.mock.calls.length).toBe(1);
28+
document.body.appendChild(container);
29+
document.body.appendChild(otherNode);
30+
31+
otherNode.dispatchEvent(
32+
new MouseEvent('mouseout', {
33+
bubbles: true,
34+
cancelable: true,
35+
relatedTarget: node,
36+
}),
37+
);
38+
expect(mock).toBeCalled();
5039
});
5140

5241
describe('Propagation', () => {
5342
it('should propagate events one level down', () => {
43+
var mouseOut = jest.fn();
44+
var onMouseOut = event => mouseOut(event.currentTarget);
45+
5446
var childContainer = document.createElement('div');
55-
var childControl = <div>Child</div>;
5647
var parentContainer = document.createElement('div');
57-
var parentControl = <div>Parent</div>;
58-
childControl = ReactDOM.render(childControl, childContainer);
59-
parentControl = ReactDOM.render(parentControl, parentContainer);
60-
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
61-
62-
var callback = ReactDOMEventListener.dispatchEvent.bind(null, 'test');
63-
callback({
64-
target: ReactDOM.findDOMNode(childControl),
65-
});
66-
67-
var calls = handleTopLevel.mock.calls;
68-
expect(calls.length).toBe(2);
69-
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
70-
ReactDOMComponentTree.getInstanceFromNode(childControl),
48+
var childNode = ReactDOM.render(
49+
<div onMouseOut={onMouseOut}>Child</div>,
50+
childContainer,
7151
);
72-
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
73-
ReactDOMComponentTree.getInstanceFromNode(parentControl),
52+
var parentNode = ReactDOM.render(
53+
<div onMouseOut={onMouseOut}>div</div>,
54+
parentContainer,
7455
);
56+
parentNode.appendChild(childContainer);
57+
document.body.appendChild(parentContainer);
58+
59+
var nativeEvent = document.createEvent('Event');
60+
nativeEvent.initEvent('mouseout', true, true);
61+
childNode.dispatchEvent(nativeEvent);
62+
63+
expect(mouseOut).toBeCalled();
64+
expect(mouseOut.mock.calls.length).toBe(2);
65+
expect(mouseOut.mock.calls[0][0]).toEqual(childNode);
66+
expect(mouseOut.mock.calls[1][0]).toEqual(parentNode);
67+
68+
document.body.removeChild(parentContainer);
7569
});
7670

7771
it('should propagate events two levels down', () => {
72+
var mouseOut = jest.fn();
73+
var onMouseOut = event => mouseOut(event.currentTarget);
74+
7875
var childContainer = document.createElement('div');
79-
var childControl = <div>Child</div>;
8076
var parentContainer = document.createElement('div');
81-
var parentControl = <div>Parent</div>;
8277
var grandParentContainer = document.createElement('div');
83-
var grandParentControl = <div>Parent</div>;
84-
childControl = ReactDOM.render(childControl, childContainer);
85-
parentControl = ReactDOM.render(parentControl, parentContainer);
86-
grandParentControl = ReactDOM.render(
87-
grandParentControl,
88-
grandParentContainer,
89-
);
90-
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
91-
ReactDOM.findDOMNode(grandParentControl).appendChild(parentContainer);
92-
93-
var callback = ReactDOMEventListener.dispatchEvent.bind(null, 'test');
94-
callback({
95-
target: ReactDOM.findDOMNode(childControl),
96-
});
97-
98-
var calls = handleTopLevel.mock.calls;
99-
expect(calls.length).toBe(3);
100-
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
101-
ReactDOMComponentTree.getInstanceFromNode(childControl),
78+
var childNode = ReactDOM.render(
79+
<div onMouseOut={onMouseOut}>Child</div>,
80+
childContainer,
10281
);
103-
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
104-
ReactDOMComponentTree.getInstanceFromNode(parentControl),
82+
var parentNode = ReactDOM.render(
83+
<div onMouseOut={onMouseOut}>Parent</div>,
84+
parentContainer,
10585
);
106-
expect(calls[2][EVENT_TARGET_PARAM]).toBe(
107-
ReactDOMComponentTree.getInstanceFromNode(grandParentControl),
86+
var grandParentNode = ReactDOM.render(
87+
<div onMouseOut={onMouseOut}>Parent</div>,
88+
grandParentContainer,
10889
);
90+
parentNode.appendChild(childContainer);
91+
grandParentNode.appendChild(parentContainer);
92+
93+
document.body.appendChild(grandParentContainer);
94+
95+
var nativeEvent = document.createEvent('Event');
96+
nativeEvent.initEvent('mouseout', true, true);
97+
childNode.dispatchEvent(nativeEvent);
98+
99+
expect(mouseOut).toBeCalled();
100+
expect(mouseOut.mock.calls.length).toBe(3);
101+
expect(mouseOut.mock.calls[0][0]).toEqual(childNode);
102+
expect(mouseOut.mock.calls[1][0]).toEqual(parentNode);
103+
expect(mouseOut.mock.calls[2][0]).toEqual(grandParentNode);
104+
105+
document.body.removeChild(grandParentContainer);
109106
});
110107

108+
// Regression test for https://github.com/facebook/react/issues/1105
111109
it('should not get confused by disappearing elements', () => {
112-
var childContainer = document.createElement('div');
113-
var childControl = <div>Child</div>;
114-
var parentContainer = document.createElement('div');
115-
var parentControl = <div>Parent</div>;
116-
childControl = ReactDOM.render(childControl, childContainer);
117-
parentControl = ReactDOM.render(parentControl, parentContainer);
118-
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
119-
120-
// ReactBrowserEventEmitter.handleTopLevel might remove the
121-
// target from the DOM. Here, we have handleTopLevel remove the
122-
// node when the first event handlers are called; we'll still
123-
// expect to receive a second call for the parent control.
124-
var childNode = ReactDOM.findDOMNode(childControl);
125-
handleTopLevel.mockImplementation(function(
126-
topLevelType,
127-
topLevelTarget,
128-
topLevelTargetID,
129-
nativeEvent,
130-
) {
131-
if (topLevelTarget === childNode) {
132-
ReactDOM.unmountComponentAtNode(childContainer);
110+
var container = document.createElement('div');
111+
document.body.appendChild(container);
112+
class MyComponent extends React.Component {
113+
state = {clicked: false};
114+
handleClick = () => {
115+
this.setState({clicked: true});
116+
};
117+
componentDidMount() {
118+
expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild);
133119
}
134-
});
135-
136-
var callback = ReactDOMEventListener.dispatchEvent.bind(null, 'test');
137-
callback({
138-
target: childNode,
139-
});
140-
141-
var calls = handleTopLevel.mock.calls;
142-
expect(calls.length).toBe(2);
143-
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
144-
ReactDOMComponentTree.getInstanceFromNode(childNode),
145-
);
146-
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
147-
ReactDOMComponentTree.getInstanceFromNode(parentControl),
120+
componentDidUpdate() {
121+
expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild);
122+
}
123+
render() {
124+
if (this.state.clicked) {
125+
return <span>clicked!</span>;
126+
} else {
127+
return <button onClick={this.handleClick}>not yet clicked</button>;
128+
}
129+
}
130+
}
131+
ReactDOM.render(<MyComponent />, container);
132+
container.firstChild.dispatchEvent(
133+
new MouseEvent('click', {
134+
bubbles: true,
135+
}),
148136
);
137+
expect(container.firstChild.textContent).toBe('clicked!');
138+
document.body.removeChild(container);
149139
});
150140

151141
it('should batch between handlers from different roots', () => {
142+
var mock = jest.fn();
143+
152144
var childContainer = document.createElement('div');
145+
var handleChildMouseOut = () => {
146+
ReactDOM.render(<div>1</div>, childContainer);
147+
mock(childNode.textContent);
148+
};
149+
153150
var parentContainer = document.createElement('div');
154-
var childControl = ReactDOM.render(<div>Child</div>, childContainer);
155-
var parentControl = ReactDOM.render(<div>Parent</div>, parentContainer);
156-
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
157-
158-
// Suppose an event handler in each root enqueues an update to the
159-
// childControl element -- the two updates should get batched together.
160-
var childNode = ReactDOM.findDOMNode(childControl);
161-
handleTopLevel.mockImplementation(function(
162-
topLevelType,
163-
topLevelTarget,
164-
topLevelTargetID,
165-
nativeEvent,
166-
) {
167-
ReactDOM.render(
168-
<div>{topLevelTarget === childNode ? '1' : '2'}</div>,
169-
childContainer,
170-
);
171-
// Since we're batching, neither update should yet have gone through.
172-
expect(childNode.textContent).toBe('Child');
173-
});
174-
175-
var callback = ReactDOMEventListener.dispatchEvent.bind(
176-
ReactDOMEventListener,
177-
'test',
178-
);
179-
callback({
180-
target: childNode,
181-
});
151+
var handleParentMouseOut = () => {
152+
ReactDOM.render(<div>2</div>, childContainer);
153+
mock(childNode.textContent);
154+
};
182155

183-
var calls = handleTopLevel.mock.calls;
184-
expect(calls.length).toBe(2);
156+
var childNode = ReactDOM.render(
157+
<div onMouseOut={handleChildMouseOut}>Child</div>,
158+
childContainer,
159+
);
160+
var parentNode = ReactDOM.render(
161+
<div onMouseOut={handleParentMouseOut}>Parent</div>,
162+
parentContainer,
163+
);
164+
parentNode.appendChild(childContainer);
165+
document.body.appendChild(parentContainer);
166+
167+
var nativeEvent = document.createEvent('Event');
168+
nativeEvent.initEvent('mouseout', true, true);
169+
childNode.dispatchEvent(nativeEvent);
170+
171+
// Child and parent should both call from event handlers.
172+
expect(mock.mock.calls.length).toBe(2);
173+
// The first call schedules a render of '1' into the 'Child'.
174+
// However, we're batching so it isn't flushed yet.
175+
expect(mock.mock.calls[0][0]).toBe('Child');
176+
// The first call schedules a render of '2' into the 'Child'.
177+
// We're still batching so it isn't flushed yet either.
178+
expect(mock.mock.calls[1][0]).toBe('Child');
179+
// By the time we leave the handler, the second update is flushed.
185180
expect(childNode.textContent).toBe('2');
181+
document.body.removeChild(parentContainer);
186182
});
187183
});
188184

189185
it('should not fire duplicate events for a React DOM tree', () => {
186+
var mouseOut = jest.fn();
187+
var onMouseOut = event => mouseOut(event.target);
188+
190189
class Wrapper extends React.Component {
191190
getInner = () => {
192191
return this.refs.inner;
193192
};
194193

195194
render() {
196195
var inner = <div ref="inner">Inner</div>;
197-
return <div><div id="outer">{inner}</div></div>;
196+
return <div><div onMouseOut={onMouseOut} id="outer">{inner}</div></div>;
198197
}
199198
}
200199

201-
var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
200+
var container = document.createElement('div');
201+
var instance = ReactDOM.render(<Wrapper />, container);
202202

203-
var callback = ReactDOMEventListener.dispatchEvent.bind(null, 'test');
204-
callback({
205-
target: ReactDOM.findDOMNode(instance.getInner()),
206-
});
203+
document.body.appendChild(container);
207204

208-
var calls = handleTopLevel.mock.calls;
209-
expect(calls.length).toBe(1);
210-
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
211-
ReactDOMComponentTree.getInstanceFromNode(instance.getInner()),
212-
);
205+
var nativeEvent = document.createEvent('Event');
206+
nativeEvent.initEvent('mouseout', true, true);
207+
instance.getInner().dispatchEvent(nativeEvent);
208+
209+
expect(mouseOut).toBeCalled();
210+
expect(mouseOut.mock.calls.length).toBe(1);
211+
expect(mouseOut.mock.calls[0][0]).toEqual(instance.getInner());
212+
document.body.removeChild(container);
213213
});
214214
});

0 commit comments

Comments
 (0)