Skip to content

Commit 84aa535

Browse files
committed
Add coverage for getNodeFromInstance and implementation of getFiberCurrentPropsFromNode
- After researching usage of getNodeFromInstance we can test getNodeFromInstance dispatching some events and asserting the id of the currentTarget - After checking git blame for getFiberCurrentPropsFromNode and reading through #8607 I found a test that we can simplify to assert behavior of the function by ensuring event handler props are updated from the fiber props. Swapping out the implementation of this function with `return node[internalInstanceKey].memoizedProps` results in a failure.
1 parent e233d0e commit 84aa535

File tree

1 file changed

+67
-25
lines changed

1 file changed

+67
-25
lines changed

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

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212
describe('ReactDOMComponentTree', () => {
1313
let React;
1414
let ReactDOM;
15-
let ReactDOMServer;
1615
let container;
1716

1817
beforeEach(() => {
1918
React = require('react');
2019
ReactDOM = require('react-dom');
21-
ReactDOMServer = require('react-dom/server');
2220
container = document.createElement('div');
2321
document.body.appendChild(container);
2422
});
@@ -28,39 +26,41 @@ describe('ReactDOMComponentTree', () => {
2826
container = null;
2927
});
3028

31-
it('finds nodes for instances', () => {
32-
// This is a little hard to test directly. But refs rely on it -- so we
33-
// check that we can find a ref at arbitrary points in the tree, even if
34-
// other nodes don't have a ref.
29+
it('finds nodes for instances on events', () => {
30+
const mouseOverID = 'mouseOverID';
31+
const clickID = 'clickID';
32+
let currentTargetID = null;
33+
// the current target of an event is set to result of getNodeFromInstance
34+
// when an event is dispatched so we can test behavior by invoking
35+
// events on elements in the tree and confirming the expected node is
36+
// set as the current target
3537
class Component extends React.Component {
38+
handler = e => {
39+
currentTargetID = e.currentTarget.id;
40+
};
3641
render() {
37-
var toRef = this.props.toRef;
3842
return (
39-
<div ref={toRef === 'div' ? 'target' : null}>
40-
<h1 ref={toRef === 'h1' ? 'target' : null}>hello</h1>
41-
<p ref={toRef === 'p' ? 'target' : null}>
42-
<input ref={toRef === 'input' ? 'target' : null} />
43-
</p>
44-
goodbye.
43+
<div id={mouseOverID} onMouseOver={this.handler}>
44+
<div id={clickID} onClick={this.handler} />
4545
</div>
4646
);
4747
}
4848
}
4949

50-
function renderAndGetRef(toRef) {
51-
// We need to unmount any React components from previous assertions in
52-
// this test
53-
ReactDOM.unmountComponentAtNode(container);
54-
const elt = <Component toRef={toRef} />;
55-
container.innerHTML = ReactDOMServer.renderToString(elt);
56-
const inst = ReactDOM.hydrate(elt, container);
57-
return inst.refs.target.nodeName;
50+
function simulateMouseEvent(elem, type) {
51+
const event = new MouseEvent(type, {
52+
bubbles: true,
53+
});
54+
elem.dispatchEvent(event);
5855
}
5956

60-
expect(renderAndGetRef('div')).toBe('DIV');
61-
expect(renderAndGetRef('h1')).toBe('H1');
62-
expect(renderAndGetRef('p')).toBe('P');
63-
expect(renderAndGetRef('input')).toBe('INPUT');
57+
const component = <Component />;
58+
ReactDOM.render(component, container);
59+
expect(currentTargetID).toBe(null);
60+
simulateMouseEvent(document.getElementById(mouseOverID), 'mouseover');
61+
expect(currentTargetID).toBe(mouseOverID);
62+
simulateMouseEvent(document.getElementById(clickID), 'click');
63+
expect(currentTargetID).toBe(clickID);
6464
});
6565

6666
it('finds closest instance for node when an event happens', () => {
@@ -98,6 +98,48 @@ describe('ReactDOMComponentTree', () => {
9898
expect(currentTargetID).toBe(closestInstanceID);
9999
});
100100

101+
it('updates event handlers from fiber props', () => {
102+
let action = '';
103+
let instance;
104+
const handlerA = () => (action = 'A');
105+
const handlerB = () => (action = 'B');
106+
107+
function simulateMouseOver(target) {
108+
const event = new MouseEvent('mouseover', {
109+
bubbles: true,
110+
});
111+
target.dispatchEvent(event);
112+
}
113+
114+
class HandlerFlipper extends React.Component {
115+
state = {flip: false};
116+
flip() {
117+
this.setState({flip: true});
118+
}
119+
render() {
120+
return (
121+
<div
122+
id="update"
123+
onMouseOver={this.state.flip ? handlerB : handlerA}
124+
/>
125+
);
126+
}
127+
}
128+
129+
ReactDOM.render(
130+
<HandlerFlipper key="1" ref={n => (instance = n)} />,
131+
container,
132+
);
133+
const node = container.firstChild;
134+
simulateMouseOver(node);
135+
expect(action).toEqual('A');
136+
action = '';
137+
// Render with the other event handler.
138+
instance.flip();
139+
simulateMouseOver(node);
140+
expect(action).toEqual('B');
141+
});
142+
101143
it('finds a controlled instance from node and gets its current fiber props', () => {
102144
const inputID = 'inputID';
103145
const startValue = undefined;

0 commit comments

Comments
 (0)