10
10
import type { FrontendBridge } from 'react-devtools-shared/src/bridge' ;
11
11
import type Store from 'react-devtools-shared/src/devtools/store' ;
12
12
13
+ import { getVersionedRenderImplementation } from './utils' ;
14
+
13
15
describe ( 'ProfilingCache' , ( ) => {
14
16
let PropTypes ;
15
17
let React ;
@@ -39,8 +41,11 @@ describe('ProfilingCache', () => {
39
41
Scheduler = require ( 'scheduler' ) ;
40
42
} ) ;
41
43
44
+ const { render, getContainer} = getVersionedRenderImplementation ( ) ;
45
+
42
46
// @reactVersion >= 16.9
43
- it ( 'should collect data for each root (including ones added or mounted after profiling started)' , ( ) => {
47
+ // @reactVersion <= 18.2
48
+ it ( 'should collect data for each root (including ones added or mounted after profiling started) (legacy render)' , ( ) => {
44
49
const Parent = ( { count} ) => {
45
50
Scheduler . unstable_advanceTime ( 10 ) ;
46
51
const children = new Array ( count )
@@ -151,6 +156,116 @@ describe('ProfilingCache', () => {
151
156
} ) ;
152
157
} ) ;
153
158
159
+ // @reactVersion >= 18
160
+ it ( 'should collect data for each root (including ones added or mounted after profiling started) (createRoot)' , ( ) => {
161
+ const Parent = ( { count} ) => {
162
+ Scheduler . unstable_advanceTime ( 10 ) ;
163
+ const children = new Array ( count )
164
+ . fill ( true )
165
+ . map ( ( _ , index ) => < Child key = { index } duration = { index } /> ) ;
166
+ return (
167
+ < React . Fragment >
168
+ { children }
169
+ < MemoizedChild duration = { 1 } />
170
+ </ React . Fragment >
171
+ ) ;
172
+ } ;
173
+ const Child = ( { duration} ) => {
174
+ Scheduler . unstable_advanceTime ( duration ) ;
175
+ return null ;
176
+ } ;
177
+ const MemoizedChild = React . memo ( Child ) ;
178
+
179
+ const RootA = ( { children} ) => children ;
180
+ const RootB = ( { children} ) => children ;
181
+ const RootC = ( { children} ) => children ;
182
+
183
+ const containerA = document . createElement ( 'div' ) ;
184
+ const containerB = document . createElement ( 'div' ) ;
185
+ const containerC = document . createElement ( 'div' ) ;
186
+
187
+ const rootA = ReactDOMClient . createRoot ( containerA ) ;
188
+ const rootB = ReactDOMClient . createRoot ( containerB ) ;
189
+ const rootC = ReactDOMClient . createRoot ( containerC ) ;
190
+
191
+ utils . act ( ( ) =>
192
+ rootA . render (
193
+ < RootA >
194
+ < Parent count = { 2 } />
195
+ </ RootA > ,
196
+ ) ,
197
+ ) ;
198
+ utils . act ( ( ) =>
199
+ rootB . render (
200
+ < RootB >
201
+ < Parent count = { 1 } />
202
+ </ RootB > ,
203
+ ) ,
204
+ ) ;
205
+ utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
206
+ utils . act ( ( ) =>
207
+ rootA . render (
208
+ < RootA >
209
+ < Parent count = { 3 } />
210
+ </ RootA > ,
211
+ ) ,
212
+ ) ;
213
+ utils . act ( ( ) =>
214
+ rootC . render (
215
+ < RootC >
216
+ < Parent count = { 1 } />
217
+ </ RootC > ,
218
+ ) ,
219
+ ) ;
220
+ utils . act ( ( ) =>
221
+ rootA . render (
222
+ < RootA >
223
+ < Parent count = { 1 } />
224
+ </ RootA > ,
225
+ ) ,
226
+ ) ;
227
+ utils . act ( ( ) => rootB . unmount ( ) ) ;
228
+ utils . act ( ( ) =>
229
+ rootA . render (
230
+ < RootA >
231
+ < Parent count = { 0 } />
232
+ </ RootA > ,
233
+ ) ,
234
+ ) ;
235
+ utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
236
+ utils . act ( ( ) => rootA . unmount ( ) ) ;
237
+
238
+ const rootIDs = Array . from (
239
+ store . profilerStore . profilingData . dataForRoots . values ( ) ,
240
+ ) . map ( ( { rootID} ) => rootID ) ;
241
+ expect ( rootIDs ) . toHaveLength ( 3 ) ;
242
+
243
+ const originalProfilingDataForRoot = [ ] ;
244
+
245
+ let data = store . profilerStore . getDataForRoot ( rootIDs [ 0 ] ) ;
246
+ expect ( data . displayName ) . toMatchInlineSnapshot ( `"RootA"` ) ;
247
+ expect ( data . commitData ) . toHaveLength ( 3 ) ;
248
+ originalProfilingDataForRoot . push ( data ) ;
249
+
250
+ data = store . profilerStore . getDataForRoot ( rootIDs [ 1 ] ) ;
251
+ expect ( data . displayName ) . toMatchInlineSnapshot ( `"RootC"` ) ;
252
+ expect ( data . commitData ) . toHaveLength ( 1 ) ;
253
+ originalProfilingDataForRoot . push ( data ) ;
254
+
255
+ data = store . profilerStore . getDataForRoot ( rootIDs [ 2 ] ) ;
256
+ expect ( data . displayName ) . toMatchInlineSnapshot ( `"RootB"` ) ;
257
+ expect ( data . commitData ) . toHaveLength ( 1 ) ;
258
+ originalProfilingDataForRoot . push ( data ) ;
259
+
260
+ utils . exportImportHelper ( bridge , store ) ;
261
+
262
+ rootIDs . forEach ( ( rootID , index ) => {
263
+ const current = store . profilerStore . getDataForRoot ( rootID ) ;
264
+ const prev = originalProfilingDataForRoot [ index ] ;
265
+ expect ( current ) . toEqual ( prev ) ;
266
+ } ) ;
267
+ } ) ;
268
+
154
269
// @reactVersion >= 16.9
155
270
it ( 'should collect data for each commit' , ( ) => {
156
271
const Parent = ( { count} ) => {
@@ -171,13 +286,11 @@ describe('ProfilingCache', () => {
171
286
} ;
172
287
const MemoizedChild = React . memo ( Child ) ;
173
288
174
- const container = document . createElement ( 'div' ) ;
175
-
176
289
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
177
- utils . act ( ( ) => legacyRender ( < Parent count = { 2 } /> , container ) ) ;
178
- utils . act ( ( ) => legacyRender ( < Parent count = { 3 } /> , container ) ) ;
179
- utils . act ( ( ) => legacyRender ( < Parent count = { 1 } /> , container ) ) ;
180
- utils . act ( ( ) => legacyRender ( < Parent count = { 0 } /> , container ) ) ;
290
+ utils . act ( ( ) => render ( < Parent count = { 2 } /> ) ) ;
291
+ utils . act ( ( ) => render ( < Parent count = { 3 } /> ) ) ;
292
+ utils . act ( ( ) => render ( < Parent count = { 1 } /> ) ) ;
293
+ utils . act ( ( ) => render ( < Parent count = { 0 } /> ) ) ;
181
294
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
182
295
183
296
const rootID = store . roots [ 0 ] ;
@@ -244,19 +357,13 @@ describe('ProfilingCache', () => {
244
357
}
245
358
}
246
359
247
- const container = document . createElement ( 'div' ) ;
248
-
249
360
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
250
- utils . act ( ( ) => legacyRender ( < LegacyContextProvider /> , container ) ) ;
361
+ utils . act ( ( ) => render ( < LegacyContextProvider /> ) ) ;
251
362
expect ( instance ) . not . toBeNull ( ) ;
252
363
utils . act ( ( ) => ( instance : any ) . setState ( { count : 1 } ) ) ;
253
- utils . act ( ( ) =>
254
- legacyRender ( < LegacyContextProvider foo = { 123 } /> , container ) ,
255
- ) ;
256
- utils . act ( ( ) =>
257
- legacyRender ( < LegacyContextProvider bar = "abc" /> , container ) ,
258
- ) ;
259
- utils . act ( ( ) => legacyRender ( < LegacyContextProvider /> , container ) ) ;
364
+ utils . act ( ( ) => render ( < LegacyContextProvider foo = { 123 } /> ) ) ;
365
+ utils . act ( ( ) => render ( < LegacyContextProvider bar = "abc" /> ) ) ;
366
+ utils . act ( ( ) => render ( < LegacyContextProvider /> ) ) ;
260
367
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
261
368
262
369
const rootID = store . roots [ 0 ] ;
@@ -574,25 +681,21 @@ describe('ProfilingCache', () => {
574
681
return null ;
575
682
} ;
576
683
577
- const container = document . createElement ( 'div' ) ;
578
-
579
684
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
580
685
utils . act ( ( ) =>
581
- legacyRender (
686
+ render (
582
687
< Context . Provider value = { true } >
583
688
< Component count = { 1 } />
584
689
</ Context . Provider > ,
585
- container ,
586
690
) ,
587
691
) ;
588
692
589
693
// Second render has no changed hooks, only changed props.
590
694
utils . act ( ( ) =>
591
- legacyRender (
695
+ render (
592
696
< Context . Provider value = { true } >
593
697
< Component count = { 2 } />
594
698
</ Context . Provider > ,
595
- container ,
596
699
) ,
597
700
) ;
598
701
@@ -604,11 +707,10 @@ describe('ProfilingCache', () => {
604
707
605
708
// Fifth render has a changed context value, but no changed hook.
606
709
utils . act ( ( ) =>
607
- legacyRender (
710
+ render (
608
711
< Context . Provider value = { false } >
609
712
< Component count = { 2 } />
610
713
</ Context . Provider > ,
611
- container ,
612
714
) ,
613
715
) ;
614
716
@@ -754,9 +856,7 @@ describe('ProfilingCache', () => {
754
856
} ;
755
857
756
858
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
757
- utils . act ( ( ) =>
758
- legacyRender ( < Grandparent /> , document . createElement ( 'div' ) ) ,
759
- ) ;
859
+ utils . act ( ( ) => render ( < Grandparent /> ) ) ;
760
860
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
761
861
762
862
expect ( store ) . toMatchInlineSnapshot ( `
@@ -822,9 +922,7 @@ describe('ProfilingCache', () => {
822
922
} ;
823
923
824
924
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
825
- await utils . actAsync ( ( ) =>
826
- legacyRender ( < Parent /> , document . createElement ( 'div' ) ) ,
827
- ) ;
925
+ await utils . actAsync ( ( ) => render ( < Parent /> ) ) ;
828
926
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
829
927
830
928
const rootID = store . roots [ 0 ] ;
@@ -880,12 +978,10 @@ describe('ProfilingCache', () => {
880
978
} ;
881
979
const MemoizedChild = React . memo ( Child ) ;
882
980
883
- const container = document . createElement ( 'div' ) ;
884
-
885
981
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
886
- utils . act ( ( ) => legacyRender ( < Parent count = { 1 } /> , container ) ) ;
887
- utils . act ( ( ) => legacyRender ( < Parent count = { 2 } /> , container ) ) ;
888
- utils . act ( ( ) => legacyRender ( < Parent count = { 3 } /> , container ) ) ;
982
+ utils . act ( ( ) => render ( < Parent count = { 1 } /> ) ) ;
983
+ utils . act ( ( ) => render ( < Parent count = { 2 } /> ) ) ;
984
+ utils . act ( ( ) => render ( < Parent count = { 3 } /> ) ) ;
889
985
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
890
986
891
987
const rootID = store . roots [ 0 ] ;
@@ -940,11 +1036,11 @@ describe('ProfilingCache', () => {
940
1036
941
1037
// @reactVersion >= 18.0.0
942
1038
// @reactVersion <= 18.2.0
943
- it ( 'should handle unexpectedly shallow suspense trees for react v[18.0.0 - 18.2.0]' , ( ) => {
944
- const container = document . createElement ( 'div' ) ;
945
-
1039
+ it ( 'should handle unexpectedly shallow suspense trees for react v[18.0.0 - 18.2.0] (legacy render)' , ( ) => {
946
1040
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
947
- utils . act ( ( ) => legacyRender ( < React . Suspense /> , container ) ) ;
1041
+ utils . act ( ( ) =>
1042
+ legacyRender ( < React . Suspense /> , document . createElement ( 'div' ) ) ,
1043
+ ) ;
948
1044
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
949
1045
950
1046
const rootID = store . roots [ 0 ] ;
@@ -981,13 +1077,51 @@ describe('ProfilingCache', () => {
981
1077
` ) ;
982
1078
} ) ;
983
1079
984
- // This test is not gated.
985
- // For this test we use the current version of react, built from source.
986
- it ( 'should handle unexpectedly shallow suspense trees' , ( ) => {
987
- const container = document . createElement ( 'div' ) ;
1080
+ // @reactVersion >= 18.0.0
1081
+ // @reactVersion <= 18.2.0
1082
+ it ( 'should handle unexpectedly shallow suspense trees for react v[18.0.0 - 18.2.0] (createRoot)' , ( ) => {
1083
+ utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
1084
+ utils . act ( ( ) => render ( < React . Suspense /> ) ) ;
1085
+ utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
988
1086
1087
+ const rootID = store . roots [ 0 ] ;
1088
+ const commitData = store . profilerStore . getDataForRoot ( rootID ) . commitData ;
1089
+ expect ( commitData ) . toMatchInlineSnapshot ( `
1090
+ [
1091
+ {
1092
+ "changeDescriptions": Map {},
1093
+ "duration": 0,
1094
+ "effectDuration": null,
1095
+ "fiberActualDurations": Map {
1096
+ 1 => 0,
1097
+ 2 => 0,
1098
+ },
1099
+ "fiberSelfDurations": Map {
1100
+ 1 => 0,
1101
+ 2 => 0,
1102
+ },
1103
+ "passiveEffectDuration": null,
1104
+ "priorityLevel": "Normal",
1105
+ "timestamp": 0,
1106
+ "updaters": [
1107
+ {
1108
+ "compiledWithForget": false,
1109
+ "displayName": "createRoot()",
1110
+ "hocDisplayNames": null,
1111
+ "id": 1,
1112
+ "key": null,
1113
+ "type": 11,
1114
+ },
1115
+ ],
1116
+ },
1117
+ ]
1118
+ ` ) ;
1119
+ } ) ;
1120
+
1121
+ // @reactVersion > 18.2.0
1122
+ it ( 'should handle unexpectedly shallow suspense trees' , ( ) => {
989
1123
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
990
- utils . act ( ( ) => legacyRender ( < React . Suspense /> , container ) ) ;
1124
+ utils . act ( ( ) => render ( < React . Suspense /> ) ) ;
991
1125
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
992
1126
993
1127
const rootID = store . roots [ 0 ] ;
@@ -1012,7 +1146,7 @@ describe('ProfilingCache', () => {
1012
1146
"updaters": [
1013
1147
{
1014
1148
"compiledWithForget": false,
1015
- "displayName": "render ()",
1149
+ "displayName": "createRoot ()",
1016
1150
"hocDisplayNames": null,
1017
1151
"id": 1,
1018
1152
"key": null,
@@ -1105,13 +1239,12 @@ describe('ProfilingCache', () => {
1105
1239
1106
1240
const { Simulate} = require ( 'react-dom/test-utils' ) ;
1107
1241
1108
- const container = document . createElement ( 'div' ) ;
1109
- utils . act ( ( ) => legacyRender ( < App /> , container ) ) ;
1110
- expect ( container . textContent ) . toBe ( 'Home' ) ;
1242
+ utils . act ( ( ) => render ( < App /> ) ) ;
1243
+ expect ( getContainer ( ) . textContent ) . toBe ( 'Home' ) ;
1111
1244
utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
1112
1245
utils . act ( ( ) => Simulate . click ( linkRef . current ) ) ;
1113
1246
utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
1114
- expect ( container . textContent ) . toBe ( 'About' ) ;
1247
+ expect ( getContainer ( ) . textContent ) . toBe ( 'About' ) ;
1115
1248
} ) ;
1116
1249
1117
1250
// @reactVersion >= 18.0
0 commit comments