1111
1212let React ;
1313let ReactDOM ;
14+ let ReactDOMClient ;
1415let ReactTestUtils ;
15-
1616let TestComponent ;
17+ let act ;
18+ let theInnerDivRef ;
19+ let theInnerClassComponentRef ;
1720
1821describe ( 'refs-destruction' , ( ) => {
1922 beforeEach ( ( ) => {
2023 jest . resetModules ( ) ;
2124
2225 React = require ( 'react' ) ;
2326 ReactDOM = require ( 'react-dom' ) ;
27+ ReactDOMClient = require ( 'react-dom/client' ) ;
2428 ReactTestUtils = require ( 'react-dom/test-utils' ) ;
29+ act = require ( 'internal-test-utils' ) . act ;
2530
2631 class ClassComponent extends React . Component {
2732 render ( ) {
@@ -30,8 +35,11 @@ describe('refs-destruction', () => {
3035 }
3136
3237 TestComponent = class extends React . Component {
33- theInnerDivRef = React . createRef ( ) ;
34- theInnerClassComponentRef = React . createRef ( ) ;
38+ constructor ( props ) {
39+ super ( props ) ;
40+ theInnerDivRef = React . createRef ( ) ;
41+ theInnerClassComponentRef = React . createRef ( ) ;
42+ }
3543
3644 render ( ) {
3745 if ( this . props . destroy ) {
@@ -46,77 +54,96 @@ describe('refs-destruction', () => {
4654 } else {
4755 return (
4856 < div >
49- < div ref = { this . theInnerDivRef } />
50- < ClassComponent ref = { this . theInnerClassComponentRef } />
57+ < div ref = { theInnerDivRef } />
58+ < ClassComponent ref = { theInnerClassComponentRef } />
5159 </ div >
5260 ) ;
5361 }
5462 }
5563 } ;
5664 } ) ;
5765
58- it ( 'should remove refs when destroying the parent' , ( ) => {
66+ afterEach ( ( ) => {
67+ theInnerClassComponentRef = null ;
68+ theInnerDivRef = null ;
69+ } ) ;
70+
71+ it ( 'should remove refs when destroying the parent' , async ( ) => {
5972 const container = document . createElement ( 'div' ) ;
60- const testInstance = ReactDOM . render ( < TestComponent /> , container ) ;
73+ const root = ReactDOMClient . createRoot ( container ) ;
74+ await act ( async ( ) => {
75+ root . render ( < TestComponent /> ) ;
76+ } ) ;
6177
62- expect (
63- ReactTestUtils . isDOMComponent ( testInstance . theInnerDivRef . current ) ,
64- ) . toBe ( true ) ;
65- expect ( testInstance . theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
78+ expect ( ReactTestUtils . isDOMComponent ( theInnerDivRef . current ) ) . toBe ( true ) ;
79+ expect ( theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
6680
67- ReactDOM . unmountComponentAtNode ( container ) ;
81+ root . unmount ( ) ;
6882
69- expect ( testInstance . theInnerDivRef . current ) . toBe ( null ) ;
70- expect ( testInstance . theInnerClassComponentRef . current ) . toBe ( null ) ;
83+ expect ( theInnerDivRef . current ) . toBe ( null ) ;
84+ expect ( theInnerClassComponentRef . current ) . toBe ( null ) ;
7185 } ) ;
7286
73- it ( 'should remove refs when destroying the child' , ( ) => {
87+ it ( 'should remove refs when destroying the child' , async ( ) => {
7488 const container = document . createElement ( 'div' ) ;
75- const testInstance = ReactDOM . render ( < TestComponent /> , container ) ;
76- expect (
77- ReactTestUtils . isDOMComponent ( testInstance . theInnerDivRef . current ) ,
78- ) . toBe ( true ) ;
79- expect ( testInstance . theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
89+ const root = ReactDOMClient . createRoot ( container ) ;
90+ await act ( async ( ) => {
91+ root . render ( < TestComponent /> ) ;
92+ } ) ;
93+
94+ expect ( ReactTestUtils . isDOMComponent ( theInnerDivRef . current ) ) . toBe ( true ) ;
95+ expect ( theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
8096
81- ReactDOM . render ( < TestComponent destroy = { true } /> , container ) ;
97+ await act ( async ( ) => {
98+ root . render ( < TestComponent destroy = { true } /> ) ;
99+ } ) ;
82100
83- expect ( testInstance . theInnerDivRef . current ) . toBe ( null ) ;
84- expect ( testInstance . theInnerClassComponentRef . current ) . toBe ( null ) ;
101+ expect ( theInnerDivRef . current ) . toBe ( null ) ;
102+ expect ( theInnerClassComponentRef . current ) . toBe ( null ) ;
85103 } ) ;
86104
87- it ( 'should remove refs when removing the child ref attribute' , ( ) => {
105+ it ( 'should remove refs when removing the child ref attribute' , async ( ) => {
88106 const container = document . createElement ( 'div' ) ;
89- const testInstance = ReactDOM . render ( < TestComponent /> , container ) ;
107+ const root = ReactDOMClient . createRoot ( container ) ;
108+ await act ( async ( ) => {
109+ root . render ( < TestComponent /> ) ;
110+ } ) ;
90111
91- expect (
92- ReactTestUtils . isDOMComponent ( testInstance . theInnerDivRef . current ) ,
93- ) . toBe ( true ) ;
94- expect ( testInstance . theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
112+ expect ( ReactTestUtils . isDOMComponent ( theInnerDivRef . current ) ) . toBe ( true ) ;
113+ expect ( theInnerClassComponentRef . current ) . toBeTruthy ( ) ;
95114
96- ReactDOM . render ( < TestComponent removeRef = { true } /> , container ) ;
115+ await act ( async ( ) => {
116+ root . render ( < TestComponent removeRef = { true } /> ) ;
117+ } ) ;
97118
98- expect ( testInstance . theInnerDivRef . current ) . toBe ( null ) ;
99- expect ( testInstance . theInnerClassComponentRef . current ) . toBe ( null ) ;
119+ expect ( theInnerDivRef . current ) . toBe ( null ) ;
120+ expect ( theInnerClassComponentRef . current ) . toBe ( null ) ;
100121 } ) ;
101122
102- it ( 'should not error when destroying child with ref asynchronously' , ( ) => {
123+ it ( 'should not error when destroying child with ref asynchronously' , async ( ) => {
124+ let nestedRoot ;
103125 class Modal extends React . Component {
104126 componentDidMount ( ) {
105127 this . div = document . createElement ( 'div' ) ;
128+ nestedRoot = ReactDOMClient . createRoot ( this . div ) ;
106129 document . body . appendChild ( this . div ) ;
107130 this . componentDidUpdate ( ) ;
108131 }
109132
110133 componentDidUpdate ( ) {
111- ReactDOM . render ( < div > { this . props . children } </ div > , this . div ) ;
134+ setTimeout ( ( ) => {
135+ ReactDOM . flushSync ( ( ) => {
136+ nestedRoot . render ( < div > { this . props . children } </ div > ) ;
137+ } ) ;
138+ } , 0 ) ;
112139 }
113140
114141 componentWillUnmount ( ) {
115142 const self = this ;
116143 // some async animation
117144 setTimeout ( function ( ) {
118145 expect ( function ( ) {
119- ReactDOM . unmountComponentAtNode ( self . div ) ;
146+ nestedRoot . unmount ( ) ;
120147 } ) . not . toThrow ( ) ;
121148 document . body . removeChild ( self . div ) ;
122149 } , 0 ) ;
@@ -144,8 +171,12 @@ describe('refs-destruction', () => {
144171 }
145172
146173 const container = document . createElement ( 'div' ) ;
147- ReactDOM . render ( < App /> , container ) ;
148- ReactDOM . render ( < App hidden = { true } /> , container ) ;
149- jest . runAllTimers ( ) ;
174+ const root = ReactDOMClient . createRoot ( container ) ;
175+ await act ( async ( ) => {
176+ root . render ( < App /> ) ;
177+ } ) ;
178+ await act ( async ( ) => {
179+ root . render ( < App hidden = { true } /> ) ;
180+ } ) ;
150181 } ) ;
151182} ) ;
0 commit comments