@@ -15,6 +15,7 @@ import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
15
15
import type Store from 'react-devtools-shared/src/devtools/store' ;
16
16
import type { ProfilingDataFrontend } from 'react-devtools-shared/src/devtools/views/Profiler/types' ;
17
17
import type { ElementType } from 'react-devtools-shared/src/frontend/types' ;
18
+ import type { Node as ReactNode } from 'react' ;
18
19
19
20
import { ReactVersion } from '../../../../ReactVersions' ;
20
21
@@ -99,6 +100,123 @@ export async function actAsync(
99
100
}
100
101
}
101
102
103
+ type RenderImplementation = {
104
+ render : ( elements : ?ReactNode ) => ( ) => void ,
105
+ unmount : ( ) => void ,
106
+ createContainer : ( ) => void ,
107
+ getContainer : ( ) => ?HTMLElement ,
108
+ } ;
109
+
110
+ export function getLegacyRenderImplementation ( ) : RenderImplementation {
111
+ let ReactDOM ;
112
+ let container ;
113
+ const containersToRemove = [ ] ;
114
+
115
+ beforeEach ( ( ) => {
116
+ ReactDOM = require ( 'react-dom' ) ;
117
+
118
+ createContainer ( ) ;
119
+ } ) ;
120
+
121
+ afterEach ( ( ) => {
122
+ containersToRemove . forEach ( c => document . body . removeChild ( c ) ) ;
123
+ containersToRemove . splice ( 0 , containersToRemove . length ) ;
124
+
125
+ ReactDOM = null ;
126
+ container = null ;
127
+ } ) ;
128
+
129
+ function render ( elements ) {
130
+ withErrorsOrWarningsIgnored (
131
+ [ 'ReactDOM.render is no longer supported in React 18' ] ,
132
+ ( ) => {
133
+ ReactDOM . render ( elements , container ) ;
134
+ } ,
135
+ ) ;
136
+
137
+ return unmount ;
138
+ }
139
+
140
+ function unmount ( ) {
141
+ ReactDOM . unmountComponentAtNode ( container ) ;
142
+ }
143
+
144
+ function createContainer ( ) {
145
+ container = document . createElement ( 'div' ) ;
146
+ document . body . appendChild ( container ) ;
147
+
148
+ containersToRemove . push ( container ) ;
149
+ }
150
+
151
+ function getContainer ( ) {
152
+ return container ;
153
+ }
154
+
155
+ return {
156
+ render,
157
+ unmount,
158
+ createContainer,
159
+ getContainer,
160
+ } ;
161
+ }
162
+
163
+ export function getModernRenderImplementation ( ) : RenderImplementation {
164
+ let ReactDOMClient ;
165
+ let container ;
166
+ let root ;
167
+ const containersToRemove = [ ] ;
168
+
169
+ beforeEach ( ( ) => {
170
+ ReactDOMClient = require ( 'react-dom/client' ) ;
171
+
172
+ createContainer ( ) ;
173
+ } ) ;
174
+
175
+ afterEach ( ( ) => {
176
+ containersToRemove . forEach ( c => document . body . removeChild ( c ) ) ;
177
+ containersToRemove . splice ( 0 , containersToRemove . length ) ;
178
+
179
+ ReactDOMClient = null ;
180
+ container = null ;
181
+ root = null ;
182
+ } ) ;
183
+
184
+ function render ( elements ) {
185
+ root . render ( elements ) ;
186
+
187
+ return unmount ;
188
+ }
189
+
190
+ function unmount ( ) {
191
+ root . unmount ( ) ;
192
+ }
193
+
194
+ function createContainer ( ) {
195
+ container = document . createElement ( 'div' ) ;
196
+ document . body . appendChild ( container ) ;
197
+
198
+ root = ReactDOMClient . createRoot ( container ) ;
199
+
200
+ containersToRemove . push ( container ) ;
201
+ }
202
+
203
+ function getContainer ( ) {
204
+ return container ;
205
+ }
206
+
207
+ return {
208
+ render,
209
+ unmount,
210
+ createContainer,
211
+ getContainer,
212
+ } ;
213
+ }
214
+
215
+ export const getVersionedRenderImplementation : ( ) => RenderImplementation =
216
+ semver . lt ( requestedReactVersion , '18.0.0' )
217
+ ? getLegacyRenderImplementation
218
+ : getModernRenderImplementation ;
219
+
102
220
export function beforeEachProfiling ( ) : void {
103
221
// Mock React's timing information so that test runs are predictable.
104
222
jest . mock ( 'scheduler' , ( ) => jest . requireActual ( 'scheduler/unstable_mock' ) ) ;
0 commit comments