11
11
12
12
let React ;
13
13
let ReactDOM ;
14
+ let ReactDOMClient ;
14
15
let ReactTestUtils ;
15
-
16
16
let TestComponent ;
17
+ let act ;
18
+ let theInnerDivRef ;
19
+ let theInnerClassComponentRef ;
17
20
18
21
describe ( 'refs-destruction' , ( ) => {
19
22
beforeEach ( ( ) => {
20
23
jest . resetModules ( ) ;
21
24
22
25
React = require ( 'react' ) ;
23
26
ReactDOM = require ( 'react-dom' ) ;
27
+ ReactDOMClient = require ( 'react-dom/client' ) ;
24
28
ReactTestUtils = require ( 'react-dom/test-utils' ) ;
29
+ act = require ( 'internal-test-utils' ) . act ;
25
30
26
31
class ClassComponent extends React . Component {
27
32
render ( ) {
@@ -30,8 +35,11 @@ describe('refs-destruction', () => {
30
35
}
31
36
32
37
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
+ }
35
43
36
44
render ( ) {
37
45
if ( this . props . destroy ) {
@@ -46,77 +54,96 @@ describe('refs-destruction', () => {
46
54
} else {
47
55
return (
48
56
< div >
49
- < div ref = { this . theInnerDivRef } />
50
- < ClassComponent ref = { this . theInnerClassComponentRef } />
57
+ < div ref = { theInnerDivRef } />
58
+ < ClassComponent ref = { theInnerClassComponentRef } />
51
59
</ div >
52
60
) ;
53
61
}
54
62
}
55
63
} ;
56
64
} ) ;
57
65
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 ( ) => {
59
72
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
+ } ) ;
61
77
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 ( ) ;
66
80
67
- ReactDOM . unmountComponentAtNode ( container ) ;
81
+ root . unmount ( ) ;
68
82
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 ) ;
71
85
} ) ;
72
86
73
- it ( 'should remove refs when destroying the child' , ( ) => {
87
+ it ( 'should remove refs when destroying the child' , async ( ) => {
74
88
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 ( ) ;
80
96
81
- ReactDOM . render ( < TestComponent destroy = { true } /> , container ) ;
97
+ await act ( async ( ) => {
98
+ root . render ( < TestComponent destroy = { true } /> ) ;
99
+ } ) ;
82
100
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 ) ;
85
103
} ) ;
86
104
87
- it ( 'should remove refs when removing the child ref attribute' , ( ) => {
105
+ it ( 'should remove refs when removing the child ref attribute' , async ( ) => {
88
106
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
+ } ) ;
90
111
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 ( ) ;
95
114
96
- ReactDOM . render ( < TestComponent removeRef = { true } /> , container ) ;
115
+ await act ( async ( ) => {
116
+ root . render ( < TestComponent removeRef = { true } /> ) ;
117
+ } ) ;
97
118
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 ) ;
100
121
} ) ;
101
122
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 ;
103
125
class Modal extends React . Component {
104
126
componentDidMount ( ) {
105
127
this . div = document . createElement ( 'div' ) ;
128
+ nestedRoot = ReactDOMClient . createRoot ( this . div ) ;
106
129
document . body . appendChild ( this . div ) ;
107
130
this . componentDidUpdate ( ) ;
108
131
}
109
132
110
133
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 ) ;
112
139
}
113
140
114
141
componentWillUnmount ( ) {
115
142
const self = this ;
116
143
// some async animation
117
144
setTimeout ( function ( ) {
118
145
expect ( function ( ) {
119
- ReactDOM . unmountComponentAtNode ( self . div ) ;
146
+ nestedRoot . unmount ( ) ;
120
147
} ) . not . toThrow ( ) ;
121
148
document . body . removeChild ( self . div ) ;
122
149
} , 0 ) ;
@@ -144,8 +171,12 @@ describe('refs-destruction', () => {
144
171
}
145
172
146
173
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
+ } ) ;
150
181
} ) ;
151
182
} ) ;
0 commit comments