Skip to content

Commit 16631c0

Browse files
jackpopegaearon
authored andcommitted
Use createRoot in ReactDOMComponentTree-test (#28112)
1 parent 216031e commit 16631c0

File tree

2 files changed

+145
-98
lines changed

2 files changed

+145
-98
lines changed

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

Lines changed: 87 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111

1212
describe('ReactDOMComponentTree', () => {
1313
let React;
14-
let ReactDOM;
14+
let ReactDOMClient;
15+
let act;
1516
let container;
1617

1718
beforeEach(() => {
1819
React = require('react');
19-
ReactDOM = require('react-dom');
20+
ReactDOMClient = require('react-dom/client');
21+
act = require('internal-test-utils').act;
22+
2023
container = document.createElement('div');
2124
document.body.appendChild(container);
2225
});
@@ -26,25 +29,24 @@ describe('ReactDOMComponentTree', () => {
2629
container = null;
2730
});
2831

29-
it('finds nodes for instances on events', () => {
32+
it('finds nodes for instances on events', async () => {
3033
const mouseOverID = 'mouseOverID';
3134
const clickID = 'clickID';
3235
let currentTargetID = null;
3336
// the current target of an event is set to result of getNodeFromInstance
3437
// when an event is dispatched so we can test behavior by invoking
3538
// events on elements in the tree and confirming the expected node is
3639
// set as the current target
37-
class Component extends React.Component {
38-
handler = e => {
40+
function Component() {
41+
const handler = e => {
3942
currentTargetID = e.currentTarget.id;
4043
};
41-
render() {
42-
return (
43-
<div id={mouseOverID} onMouseOver={this.handler}>
44-
<div id={clickID} onClick={this.handler} />
45-
</div>
46-
);
47-
}
44+
45+
return (
46+
<div id={mouseOverID} onMouseOver={handler}>
47+
<div id={clickID} onClick={handler} />
48+
</div>
49+
);
4850
}
4951

5052
function simulateMouseEvent(elem, type) {
@@ -54,34 +56,35 @@ describe('ReactDOMComponentTree', () => {
5456
elem.dispatchEvent(event);
5557
}
5658

57-
const component = <Component />;
58-
ReactDOM.render(component, container);
59+
const root = ReactDOMClient.createRoot(container);
60+
await act(() => {
61+
root.render(<Component />);
62+
});
5963
expect(currentTargetID).toBe(null);
6064
simulateMouseEvent(document.getElementById(mouseOverID), 'mouseover');
6165
expect(currentTargetID).toBe(mouseOverID);
6266
simulateMouseEvent(document.getElementById(clickID), 'click');
6367
expect(currentTargetID).toBe(clickID);
6468
});
6569

66-
it('finds closest instance for node when an event happens', () => {
70+
it('finds closest instance for node when an event happens', async () => {
6771
const nonReactElemID = 'aID';
6872
const innerHTML = {__html: `<div id="${nonReactElemID}"></div>`};
6973
const closestInstanceID = 'closestInstance';
7074
let currentTargetID = null;
7175

72-
class ClosestInstance extends React.Component {
73-
_onClick = e => {
76+
function ClosestInstance() {
77+
const onClick = e => {
7478
currentTargetID = e.currentTarget.id;
7579
};
76-
render() {
77-
return (
78-
<div
79-
id={closestInstanceID}
80-
onClick={this._onClick}
81-
dangerouslySetInnerHTML={innerHTML}
82-
/>
83-
);
84-
}
80+
81+
return (
82+
<div
83+
id={closestInstanceID}
84+
onClick={onClick}
85+
dangerouslySetInnerHTML={innerHTML}
86+
/>
87+
);
8588
}
8689

8790
function simulateClick(elem) {
@@ -91,16 +94,22 @@ describe('ReactDOMComponentTree', () => {
9194
elem.dispatchEvent(event);
9295
}
9396

94-
const component = <ClosestInstance />;
95-
ReactDOM.render(<section>{component}</section>, container);
97+
const root = ReactDOMClient.createRoot(container);
98+
await act(() => {
99+
root.render(
100+
<section>
101+
<ClosestInstance />
102+
</section>,
103+
);
104+
});
96105
expect(currentTargetID).toBe(null);
97106
simulateClick(document.getElementById(nonReactElemID));
98107
expect(currentTargetID).toBe(closestInstanceID);
99108
});
100109

101-
it('updates event handlers from fiber props', () => {
110+
it('updates event handlers from fiber props', async () => {
102111
let action = '';
103-
let instance;
112+
let flip;
104113
const handlerA = () => (action = 'A');
105114
const handlerB = () => (action = 'B');
106115

@@ -111,55 +120,56 @@ describe('ReactDOMComponentTree', () => {
111120
target.dispatchEvent(event);
112121
}
113122

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-
}
123+
function HandlerFlipper() {
124+
const [flipVal, setFlipVal] = React.useState(false);
125+
flip = () => setFlipVal(true);
126+
127+
return <div id="update" onMouseOver={flipVal ? handlerB : handlerA} />;
127128
}
128129

129-
ReactDOM.render(
130-
<HandlerFlipper key="1" ref={n => (instance = n)} />,
131-
container,
132-
);
130+
const root = ReactDOMClient.createRoot(container);
131+
await act(() => {
132+
root.render(<HandlerFlipper key="1" />);
133+
});
133134
const node = container.firstChild;
134-
simulateMouseOver(node);
135+
136+
await act(() => {
137+
simulateMouseOver(node);
138+
});
135139
expect(action).toEqual('A');
136140
action = '';
141+
137142
// Render with the other event handler.
138-
instance.flip();
139-
simulateMouseOver(node);
143+
await act(() => {
144+
flip();
145+
});
146+
await act(() => {
147+
simulateMouseOver(node);
148+
});
140149
expect(action).toEqual('B');
141150
});
142151

143-
it('finds a controlled instance from node and gets its current fiber props', () => {
152+
it('finds a controlled instance from node and gets its current fiber props', async () => {
153+
let inputRef;
144154
const inputID = 'inputID';
145155
const startValue = undefined;
146156
const finishValue = 'finish';
147157

148-
class Controlled extends React.Component {
149-
state = {value: startValue};
150-
a = null;
151-
_onChange = e => this.setState({value: e.currentTarget.value});
152-
render() {
153-
return (
154-
<input
155-
id={inputID}
156-
type="text"
157-
ref={n => (this.a = n)}
158-
value={this.state.value}
159-
onChange={this._onChange}
160-
/>
161-
);
162-
}
158+
function Controlled() {
159+
const [state, setState] = React.useState(startValue);
160+
const ref = React.useRef();
161+
inputRef = ref;
162+
const onChange = e => setState(e.currentTarget.value);
163+
164+
return (
165+
<input
166+
id={inputID}
167+
type="text"
168+
ref={ref}
169+
value={state}
170+
onChange={onChange}
171+
/>
172+
);
163173
}
164174

165175
const setUntrackedInputValue = Object.getOwnPropertyDescriptor(
@@ -175,9 +185,17 @@ describe('ReactDOMComponentTree', () => {
175185
elem.dispatchEvent(inputEvent);
176186
}
177187

178-
const component = <Controlled />;
179-
const instance = ReactDOM.render(component, container);
180-
expect(() => simulateInput(instance.a, finishValue)).toErrorDev(
188+
const root = ReactDOMClient.createRoot(container);
189+
await act(() => {
190+
root.render(<Controlled />);
191+
});
192+
193+
await expect(
194+
async () =>
195+
await act(() => {
196+
simulateInput(inputRef.current, finishValue);
197+
}),
198+
).toErrorDev(
181199
'Warning: A component is changing an uncontrolled input to be controlled. ' +
182200
'This is likely caused by the value changing from undefined to ' +
183201
'a defined value, which should not happen. ' +
@@ -186,33 +204,4 @@ describe('ReactDOMComponentTree', () => {
186204
'https://reactjs.org/link/controlled-components',
187205
);
188206
});
189-
190-
it('finds instance of node that is attempted to be unmounted', () => {
191-
const component = <div />;
192-
const node = ReactDOM.render(<div>{component}</div>, container);
193-
expect(() => ReactDOM.unmountComponentAtNode(node)).toErrorDev(
194-
"unmountComponentAtNode(): The node you're attempting to unmount " +
195-
'was rendered by React and is not a top-level container. You may ' +
196-
'have accidentally passed in a React root node instead of its ' +
197-
'container.',
198-
{withoutStack: true},
199-
);
200-
});
201-
202-
it('finds instance from node to stop rendering over other react rendered components', () => {
203-
const component = (
204-
<div>
205-
<span>Hello</span>
206-
</div>
207-
);
208-
const anotherComponent = <div />;
209-
const instance = ReactDOM.render(component, container);
210-
expect(() => ReactDOM.render(anotherComponent, instance)).toErrorDev(
211-
'render(...): Replacing React-rendered children with a new root ' +
212-
'component. If you intended to update the children of this node, ' +
213-
'you should instead have the existing children update their state ' +
214-
'and render the new components instead of calling ReactDOM.render.',
215-
{withoutStack: true},
216-
);
217-
});
218207
});
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
*/
9+
10+
'use strict';
11+
12+
describe('ReactDOMComponentTree', () => {
13+
let React;
14+
let ReactDOM;
15+
let container;
16+
17+
beforeEach(() => {
18+
React = require('react');
19+
ReactDOM = require('react-dom');
20+
21+
container = document.createElement('div');
22+
document.body.appendChild(container);
23+
});
24+
25+
afterEach(() => {
26+
document.body.removeChild(container);
27+
container = null;
28+
});
29+
30+
it('finds instance of node that is attempted to be unmounted', () => {
31+
const component = <div />;
32+
const node = ReactDOM.render(<div>{component}</div>, container);
33+
expect(() => ReactDOM.unmountComponentAtNode(node)).toErrorDev(
34+
"unmountComponentAtNode(): The node you're attempting to unmount " +
35+
'was rendered by React and is not a top-level container. You may ' +
36+
'have accidentally passed in a React root node instead of its ' +
37+
'container.',
38+
{withoutStack: true},
39+
);
40+
});
41+
42+
it('finds instance from node to stop rendering over other react rendered components', () => {
43+
const component = (
44+
<div>
45+
<span>Hello</span>
46+
</div>
47+
);
48+
const anotherComponent = <div />;
49+
const instance = ReactDOM.render(component, container);
50+
expect(() => ReactDOM.render(anotherComponent, instance)).toErrorDev(
51+
'render(...): Replacing React-rendered children with a new root ' +
52+
'component. If you intended to update the children of this node, ' +
53+
'you should instead have the existing children update their state ' +
54+
'and render the new components instead of calling ReactDOM.render.',
55+
{withoutStack: true},
56+
);
57+
});
58+
});

0 commit comments

Comments
 (0)