Convert ReactMultiChildReconcile to createRoot (#28169)
Sebastian Silbermann committed
Feb 4, 2024 at 15:44 UTC
214fe84f53c5ba9d40c3427b72c5e6fb9be830e5
1 file changed
+185
-126
packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js
+185
-126
@@ -10,7 +10,8 @@
10
'use strict';
11
12
const React = require('react');
13
-const ReactDOM = require('react-dom');
13
+const ReactDOMClient = require('react-dom/client');
14
+const act = require('internal-test-utils').act;
15
16
const stripEmptyValues = function (obj) {
17
const ret = {};
@@ -221,24 +222,40 @@ function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
222
expect(orderedDomKeys).toEqual(orderedLogicalKeys);
223
}
224
224
-function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) {
225
+async function testPropsSequenceWithPreparedChildren(
226
+ sequence,
227
+ prepareChildren,
228
+) {
229
const container = document.createElement('div');
226
- const parentInstance = ReactDOM.render(
227
- <FriendsStatusDisplay {...sequence[0]} prepareChildren={prepareChildren} />,
228
- container,
229
- );
230
+ const root = ReactDOMClient.createRoot(container);
231
+ let parentInstance;
232
+ await act(() => {
233
+ root.render(
234
+ <FriendsStatusDisplay
235
+ {...sequence[0]}
236
+ prepareChildren={prepareChildren}
237
+ ref={current => {
238
+ if (parentInstance === undefined) {
239
+ parentInstance = current;
240
+ }
241
+ }}
242
+ />,
243
+ );
244
+ });
245
let statusDisplays = parentInstance.getStatusDisplays();
246
let lastInternalStates = getInternalStateByUserName(statusDisplays);
247
verifyStatuses(statusDisplays, sequence[0]);
248
249
for (let i = 1; i < sequence.length; i++) {
235
- ReactDOM.render(
236
- <FriendsStatusDisplay
237
- {...sequence[i]}
238
- prepareChildren={prepareChildren}
239
- />,
240
- container,
241
- );
250
+ await act(() => {
251
+ root.render(
252
+ <FriendsStatusDisplay
253
+ {...sequence[i]}
254
+ prepareChildren={prepareChildren}
255
+ />,
256
+ );
257
+ });
258
+
259
statusDisplays = parentInstance.getStatusDisplays();
260
verifyStatuses(statusDisplays, sequence[i]);
261
verifyStatesPreserved(lastInternalStates, statusDisplays);
@@ -274,13 +291,13 @@ function prepareChildrenModernIterable(childrenArray) {
291
};
292
}
293
277
-function testPropsSequence(sequence) {
278
- testPropsSequenceWithPreparedChildren(sequence, prepareChildrenArray);
279
- testPropsSequenceWithPreparedChildren(
294
+async function testPropsSequence(sequence) {
295
+ await testPropsSequenceWithPreparedChildren(sequence, prepareChildrenArray);
296
+ await testPropsSequenceWithPreparedChildren(
297
sequence,
298
prepareChildrenLegacyIterable,
299
);
283
- testPropsSequenceWithPreparedChildren(
300
+ await testPropsSequenceWithPreparedChildren(
301
sequence,
302
prepareChildrenModernIterable,
303
);
@@ -291,7 +308,7 @@ describe('ReactMultiChildReconcile', () => {
308
jest.resetModules();
309
});
310
294
- it('should reset internal state if removed then readded in an array', () => {
311
+ it('should reset internal state if removed then readded in an array', async () => {
312
// Test basics.
313
const props = {
314
usernameToStatus: {
@@ -300,32 +317,44 @@ describe('ReactMultiChildReconcile', () => {
317
};
318
319
const container = document.createElement('div');
303
- const parentInstance = ReactDOM.render(
304
- <FriendsStatusDisplay
305
- {...props}
306
- prepareChildren={prepareChildrenArray}
307
- />,
308
- container,
309
- );
320
+ const root = ReactDOMClient.createRoot(container);
321
+ let parentInstance;
322
+ await act(() => {
323
+ root.render(
324
+ <FriendsStatusDisplay
325
+ {...props}
326
+ prepareChildren={prepareChildrenArray}
327
+ ref={current => {
328
+ if (parentInstance === undefined) {
329
+ parentInstance = current;
330
+ }
331
+ }}
332
+ />,
333
+ );
334
+ });
335
let statusDisplays = parentInstance.getStatusDisplays();
336
const startingInternalState = statusDisplays.jcw.getInternalState();
337
338
// Now remove the child.
314
- ReactDOM.render(
315
- <FriendsStatusDisplay prepareChildren={prepareChildrenArray} />,
316
- container,
317
- );
339
+ await act(() => {
340
+ root.render(
341
+ <FriendsStatusDisplay prepareChildren={prepareChildrenArray} />,
342
+ );
343
+ });
344
+
345
statusDisplays = parentInstance.getStatusDisplays();
346
expect(statusDisplays.jcw).toBeFalsy();
347
348
// Now reset the props that cause there to be a child
322
- ReactDOM.render(
323
- <FriendsStatusDisplay
324
- {...props}
325
- prepareChildren={prepareChildrenArray}
326
- />,
327
- container,
328
- );
349
+ await act(() => {
350
+ root.render(
351
+ <FriendsStatusDisplay
352
+ {...props}
353
+ prepareChildren={prepareChildrenArray}
354
+ />,
355
+ );
356
+ });
357
+
358
statusDisplays = parentInstance.getStatusDisplays();
359
expect(statusDisplays.jcw).toBeTruthy();
360
expect(statusDisplays.jcw.getInternalState()).not.toBe(
@@ -333,7 +362,7 @@ describe('ReactMultiChildReconcile', () => {
362
);
363
});
364
336
- it('should reset internal state if removed then readded in a legacy iterable', () => {
365
+ it('should reset internal state if removed then readded in a legacy iterable', async () => {
366
// Test basics.
367
const props = {
368
usernameToStatus: {
@@ -342,32 +371,47 @@ describe('ReactMultiChildReconcile', () => {
371
};
372
373
const container = document.createElement('div');
345
- const parentInstance = ReactDOM.render(
346
- <FriendsStatusDisplay
347
- {...props}
348
- prepareChildren={prepareChildrenLegacyIterable}
349
- />,
350
- container,
351
- );
374
+ const root = ReactDOMClient.createRoot(container);
375
+ let parentInstance;
376
+ await act(() => {
377
+ root.render(
378
+ <FriendsStatusDisplay
379
+ {...props}
380
+ prepareChildren={prepareChildrenLegacyIterable}
381
+ ref={current => {
382
+ if (parentInstance === undefined) {
383
+ parentInstance = current;
384
+ }
385
+ }}
386
+ />,
387
+ );
388
+ });
389
+
390
let statusDisplays = parentInstance.getStatusDisplays();
391
const startingInternalState = statusDisplays.jcw.getInternalState();
392
393
// Now remove the child.
356
- ReactDOM.render(
357
- <FriendsStatusDisplay prepareChildren={prepareChildrenLegacyIterable} />,
358
- container,
359
- );
394
+ await act(() => {
395
+ root.render(
396
+ <FriendsStatusDisplay
397
+ prepareChildren={prepareChildrenLegacyIterable}
398
+ />,
399
+ );
400
+ });
401
+
402
statusDisplays = parentInstance.getStatusDisplays();
403
expect(statusDisplays.jcw).toBeFalsy();
404
405
// Now reset the props that cause there to be a child
364
- ReactDOM.render(
365
- <FriendsStatusDisplay
366
- {...props}
367
- prepareChildren={prepareChildrenLegacyIterable}
368
- />,
369
- container,
370
- );
406
+ await act(() => {
407
+ root.render(
408
+ <FriendsStatusDisplay
409
+ {...props}
410
+ prepareChildren={prepareChildrenLegacyIterable}
411
+ />,
412
+ );
413
+ });
414
+
415
statusDisplays = parentInstance.getStatusDisplays();
416
expect(statusDisplays.jcw).toBeTruthy();
417
expect(statusDisplays.jcw.getInternalState()).not.toBe(
@@ -375,7 +419,7 @@ describe('ReactMultiChildReconcile', () => {
419
);
420
});
421
378
- it('should reset internal state if removed then readded in a modern iterable', () => {
422
+ it('should reset internal state if removed then readded in a modern iterable', async () => {
423
// Test basics.
424
const props = {
425
usernameToStatus: {
@@ -384,32 +428,47 @@ describe('ReactMultiChildReconcile', () => {
428
};
429
430
const container = document.createElement('div');
387
- const parentInstance = ReactDOM.render(
388
- <FriendsStatusDisplay
389
- {...props}
390
- prepareChildren={prepareChildrenModernIterable}
391
- />,
392
- container,
393
- );
431
+ const root = ReactDOMClient.createRoot(container);
432
+ let parentInstance;
433
+ await act(() => {
434
+ root.render(
435
+ <FriendsStatusDisplay
436
+ {...props}
437
+ prepareChildren={prepareChildrenModernIterable}
438
+ ref={current => {
439
+ if (parentInstance === undefined) {
440
+ parentInstance = current;
441
+ }
442
+ }}
443
+ />,
444
+ );
445
+ });
446
+
447
let statusDisplays = parentInstance.getStatusDisplays();
448
const startingInternalState = statusDisplays.jcw.getInternalState();
449
450
// Now remove the child.
398
- ReactDOM.render(
399
- <FriendsStatusDisplay prepareChildren={prepareChildrenModernIterable} />,
400
- container,
401
- );
451
+ await act(() => {
452
+ root.render(
453
+ <FriendsStatusDisplay
454
+ prepareChildren={prepareChildrenModernIterable}
455
+ />,
456
+ );
457
+ });
458
+
459
statusDisplays = parentInstance.getStatusDisplays();
460
expect(statusDisplays.jcw).toBeFalsy();
461
462
// Now reset the props that cause there to be a child
406
- ReactDOM.render(
407
- <FriendsStatusDisplay
408
- {...props}
409
- prepareChildren={prepareChildrenModernIterable}
410
- />,
411
- container,
412
- );
463
+ await act(() => {
464
+ root.render(
465
+ <FriendsStatusDisplay
466
+ {...props}
467
+ prepareChildren={prepareChildrenModernIterable}
468
+ />,
469
+ );
470
+ });
471
+
472
statusDisplays = parentInstance.getStatusDisplays();
473
expect(statusDisplays.jcw).toBeTruthy();
474
expect(statusDisplays.jcw.getInternalState()).not.toBe(
@@ -417,7 +476,7 @@ describe('ReactMultiChildReconcile', () => {
476
);
477
});
478
420
- it('should create unique identity', () => {
479
+ it('should create unique identity', async () => {
480
// Test basics.
481
const usernameToStatus = {
482
jcw: 'jcwStatus',
@@ -425,10 +484,10 @@ describe('ReactMultiChildReconcile', () => {
484
bob: 'bobStatus',
485
};
486
428
- testPropsSequence([{usernameToStatus: usernameToStatus}]);
487
+ await testPropsSequence([{usernameToStatus: usernameToStatus}]);
488
});
489
431
- it('should preserve order if children order has not changed', () => {
490
+ it('should preserve order if children order has not changed', async () => {
491
const PROPS_SEQUENCE = [
492
{
493
usernameToStatus: {
@@ -443,10 +502,10 @@ describe('ReactMultiChildReconcile', () => {
502
},
503
},
504
];
446
- testPropsSequence(PROPS_SEQUENCE);
505
+ await testPropsSequence(PROPS_SEQUENCE);
506
});
507
449
- it('should transition from zero to one children correctly', () => {
508
+ it('should transition from zero to one children correctly', async () => {
509
const PROPS_SEQUENCE = [
510
{usernameToStatus: {}},
511
{
@@ -455,10 +514,10 @@ describe('ReactMultiChildReconcile', () => {
514
},
515
},
516
];
458
- testPropsSequence(PROPS_SEQUENCE);
517
+ await testPropsSequence(PROPS_SEQUENCE);
518
});
519
461
- it('should transition from one to zero children correctly', () => {
520
+ it('should transition from one to zero children correctly', async () => {
521
const PROPS_SEQUENCE = [
522
{
523
usernameToStatus: {
@@ -467,11 +526,11 @@ describe('ReactMultiChildReconcile', () => {
526
},
527
{usernameToStatus: {}},
528
];
470
- testPropsSequence(PROPS_SEQUENCE);
529
+ await testPropsSequence(PROPS_SEQUENCE);
530
});
531
473
- it('should transition from one child to null children', () => {
474
- testPropsSequence([
532
+ it('should transition from one child to null children', async () => {
533
+ await testPropsSequence([
534
{
535
usernameToStatus: {
536
first: 'firstStatus',
@@ -481,8 +540,8 @@ describe('ReactMultiChildReconcile', () => {
540
]);
541
});
542
484
- it('should transition from null children to one child', () => {
485
- testPropsSequence([
543
+ it('should transition from null children to one child', async () => {
544
+ await testPropsSequence([
545
{},
546
{
547
usernameToStatus: {
@@ -492,8 +551,8 @@ describe('ReactMultiChildReconcile', () => {
551
]);
552
});
553
495
- it('should transition from zero children to null children', () => {
496
- testPropsSequence([
554
+ it('should transition from zero children to null children', async () => {
555
+ await testPropsSequence([
556
{
557
usernameToStatus: {},
558
},
@@ -501,8 +560,8 @@ describe('ReactMultiChildReconcile', () => {
560
]);
561
});
562
504
- it('should transition from null children to zero children', () => {
505
- testPropsSequence([
563
+ it('should transition from null children to zero children', async () => {
564
+ await testPropsSequence([
565
{},
566
{
567
usernameToStatus: {},
@@ -514,7 +573,7 @@ describe('ReactMultiChildReconcile', () => {
573
* `FriendsStatusDisplay` renders nulls as empty children (it's a convention
574
* of `FriendsStatusDisplay`, nothing related to React or these test cases.
575
*/
517
- it('should remove nulled out children at the beginning', () => {
576
+ it('should remove nulled out children at the beginning', async () => {
577
const PROPS_SEQUENCE = [
578
{
579
usernameToStatus: {
@@ -529,10 +588,10 @@ describe('ReactMultiChildReconcile', () => {
588
},
589
},
590
];
532
- testPropsSequence(PROPS_SEQUENCE);
591
+ await testPropsSequence(PROPS_SEQUENCE);
592
});
593
535
- it('should remove nulled out children at the end', () => {
594
+ it('should remove nulled out children at the end', async () => {
595
const PROPS_SEQUENCE = [
596
{
597
usernameToStatus: {
@@ -547,10 +606,10 @@ describe('ReactMultiChildReconcile', () => {
606
},
607
},
608
];
550
- testPropsSequence(PROPS_SEQUENCE);
609
+ await testPropsSequence(PROPS_SEQUENCE);
610
});
611
553
- it('should reverse the order of two children', () => {
612
+ it('should reverse the order of two children', async () => {
613
const PROPS_SEQUENCE = [
614
{
615
usernameToStatus: {
@@ -565,10 +624,10 @@ describe('ReactMultiChildReconcile', () => {
624
},
625
},
626
];
568
- testPropsSequence(PROPS_SEQUENCE);
627
+ await testPropsSequence(PROPS_SEQUENCE);
628
});
629
571
- it('should reverse the order of more than two children', () => {
630
+ it('should reverse the order of more than two children', async () => {
631
const PROPS_SEQUENCE = [
632
{
633
usernameToStatus: {
@@ -585,10 +644,10 @@ describe('ReactMultiChildReconcile', () => {
644
},
645
},
646
];
588
- testPropsSequence(PROPS_SEQUENCE);
647
+ await testPropsSequence(PROPS_SEQUENCE);
648
});
649
591
- it('should cycle order correctly', () => {
650
+ it('should cycle order correctly', async () => {
651
const PROPS_SEQUENCE = [
652
{
653
usernameToStatus: {
@@ -632,10 +691,10 @@ describe('ReactMultiChildReconcile', () => {
691
},
692
},
693
];
635
- testPropsSequence(PROPS_SEQUENCE);
694
+ await testPropsSequence(PROPS_SEQUENCE);
695
});
696
638
- it('should cycle order correctly in the other direction', () => {
697
+ it('should cycle order correctly in the other direction', async () => {
698
const PROPS_SEQUENCE = [
699
{
700
usernameToStatus: {
@@ -679,10 +738,10 @@ describe('ReactMultiChildReconcile', () => {
738
},
739
},
740
];
682
- testPropsSequence(PROPS_SEQUENCE);
741
+ await testPropsSequence(PROPS_SEQUENCE);
742
});
743
685
- it('should remove nulled out children and ignore new null children', () => {
744
+ it('should remove nulled out children and ignore new null children', async () => {
745
const PROPS_SEQUENCE = [
746
{
747
usernameToStatus: {
@@ -698,10 +757,10 @@ describe('ReactMultiChildReconcile', () => {
757
},
758
},
759
];
701
- testPropsSequence(PROPS_SEQUENCE);
760
+ await testPropsSequence(PROPS_SEQUENCE);
761
});
762
704
- it('should remove nulled out children and reorder remaining', () => {
763
+ it('should remove nulled out children and reorder remaining', async () => {
764
const PROPS_SEQUENCE = [
765
{
766
usernameToStatus: {
@@ -719,10 +778,10 @@ describe('ReactMultiChildReconcile', () => {
778
},
779
},
780
];
722
- testPropsSequence(PROPS_SEQUENCE);
781
+ await testPropsSequence(PROPS_SEQUENCE);
782
});
783
725
- it('should append children to the end', () => {
784
+ it('should append children to the end', async () => {
785
const PROPS_SEQUENCE = [
786
{
787
usernameToStatus: {
@@ -738,10 +797,10 @@ describe('ReactMultiChildReconcile', () => {
797
},
798
},
799
];
741
- testPropsSequence(PROPS_SEQUENCE);
800
+ await testPropsSequence(PROPS_SEQUENCE);
801
});
802
744
- it('should append multiple children to the end', () => {
803
+ it('should append multiple children to the end', async () => {
804
const PROPS_SEQUENCE = [
805
{
806
usernameToStatus: {
@@ -758,10 +817,10 @@ describe('ReactMultiChildReconcile', () => {
817
},
818
},
819
];
761
- testPropsSequence(PROPS_SEQUENCE);
820
+ await testPropsSequence(PROPS_SEQUENCE);
821
});
822
764
- it('should prepend children to the beginning', () => {
823
+ it('should prepend children to the beginning', async () => {
824
const PROPS_SEQUENCE = [
825
{
826
usernameToStatus: {
@@ -777,10 +836,10 @@ describe('ReactMultiChildReconcile', () => {
836
},
837
},
838
];
780
- testPropsSequence(PROPS_SEQUENCE);
839
+ await testPropsSequence(PROPS_SEQUENCE);
840
});
841
783
- it('should prepend multiple children to the beginning', () => {
842
+ it('should prepend multiple children to the beginning', async () => {
843
const PROPS_SEQUENCE = [
844
{
845
usernameToStatus: {
@@ -797,10 +856,10 @@ describe('ReactMultiChildReconcile', () => {
856
},
857
},
858
];
800
- testPropsSequence(PROPS_SEQUENCE);
859
+ await testPropsSequence(PROPS_SEQUENCE);
860
});
861
803
- it('should not prepend an empty child to the beginning', () => {
862
+ it('should not prepend an empty child to the beginning', async () => {
863
const PROPS_SEQUENCE = [
864
{
865
usernameToStatus: {
@@ -816,10 +875,10 @@ describe('ReactMultiChildReconcile', () => {
875
},
876
},
877
];
819
- testPropsSequence(PROPS_SEQUENCE);
878
+ await testPropsSequence(PROPS_SEQUENCE);
879
});
880
822
- it('should not append an empty child to the end', () => {
881
+ it('should not append an empty child to the end', async () => {
882
const PROPS_SEQUENCE = [
883
{
884
usernameToStatus: {
@@ -835,10 +894,10 @@ describe('ReactMultiChildReconcile', () => {
894
},
895
},
896
];
838
- testPropsSequence(PROPS_SEQUENCE);
897
+ await testPropsSequence(PROPS_SEQUENCE);
898
});
899
841
- it('should not insert empty children in the middle', () => {
900
+ it('should not insert empty children in the middle', async () => {
901
const PROPS_SEQUENCE = [
902
{
903
usernameToStatus: {
@@ -856,10 +915,10 @@ describe('ReactMultiChildReconcile', () => {
915
},
916
},
917
];
859
- testPropsSequence(PROPS_SEQUENCE);
918
+ await testPropsSequence(PROPS_SEQUENCE);
919
});
920
862
- it('should insert one new child in the middle', () => {
921
+ it('should insert one new child in the middle', async () => {
922
const PROPS_SEQUENCE = [
923
{
924
usernameToStatus: {
@@ -875,10 +934,10 @@ describe('ReactMultiChildReconcile', () => {
934
},
935
},
936
];
878
- testPropsSequence(PROPS_SEQUENCE);
937
+ await testPropsSequence(PROPS_SEQUENCE);
938
});
939
881
- it('should insert multiple new truthy children in the middle', () => {
940
+ it('should insert multiple new truthy children in the middle', async () => {
941
const PROPS_SEQUENCE = [
942
{
943
usernameToStatus: {
@@ -896,10 +955,10 @@ describe('ReactMultiChildReconcile', () => {
955
},
956
},
957
];
899
- testPropsSequence(PROPS_SEQUENCE);
958
+ await testPropsSequence(PROPS_SEQUENCE);
959
});
960
902
- it('should insert non-empty children in middle where nulls were', () => {
961
+ it('should insert non-empty children in middle where nulls were', async () => {
962
const PROPS_SEQUENCE = [
963
{
964
usernameToStatus: {
@@ -920,6 +979,6 @@ describe('ReactMultiChildReconcile', () => {
979
},
980
},
981
];
923
- testPropsSequence(PROPS_SEQUENCE);
982
+ await testPropsSequence(PROPS_SEQUENCE);
983
});
984
});