1111
1212describe ( '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} ) ;
0 commit comments