1268
expect(componentStackMessage).toContain('in Lazy');
1269
});
1270
1271
+ // @gate enableLazyElements
1272
+ it('mount and reorder lazy types', async () => {
1273
+ class Child extends React.Component {
1274
+ componentDidMount() {
1275
+ Scheduler.unstable_yieldValue('Did mount: ' + this.props.label);
1276
+ }
1277
+ componentDidUpdate() {
1278
+ Scheduler.unstable_yieldValue('Did update: ' + this.props.label);
1279
+ }
1280
+ render() {
1281
+ return <Text text={this.props.label} />;
1282
+ }
1283
+ }
1284
+
1285
+ function ChildA({lowerCase}) {
1286
+ return <Child label={lowerCase ? 'a' : 'A'} />;
1287
+ }
1288
+
1289
+ function ChildB({lowerCase}) {
1290
+ return <Child label={lowerCase ? 'b' : 'B'} />;
1291
+ }
1292
+
1293
+ const LazyChildA = lazy(() => {
1294
+ Scheduler.unstable_yieldValue('Init A');
1295
+ return fakeImport(ChildA);
1296
+ });
1297
+ const LazyChildB = lazy(() => {
1298
+ Scheduler.unstable_yieldValue('Init B');
1299
+ return fakeImport(ChildB);
1300
+ });
1301
+ const LazyChildA2 = lazy(() => {
1302
+ Scheduler.unstable_yieldValue('Init A2');
1303
+ return fakeImport(ChildA);
1304
+ });
1305
+ let resolveB2;
1306
+ const LazyChildB2 = lazy(() => {
1307
+ Scheduler.unstable_yieldValue('Init B2');
1308
+ return new Promise(r => {
1309
+ resolveB2 = r;
1310
+ });
1311
+ });
1312
+
1313
+ function Parent({swap}) {
1314
+ return (
1315
+ <Suspense fallback={<Text text="Outer..." />}>
1316
+ <Suspense fallback={<Text text="Loading..." />}>
1317
+ {swap
1318
+ ? [
1319
+ <LazyChildB2 key="B" lowerCase={true} />,
1320
+ <LazyChildA2 key="A" lowerCase={true} />,
1321
+ ]
1322
+ : [<LazyChildA key="A" />, <LazyChildB key="B" />]}
1323
+ </Suspense>
1324
+ </Suspense>
1325
+ );
1326
+ }
1327
+
1328
+ const root = ReactTestRenderer.create(<Parent swap={false} />, {
1329
+ unstable_isConcurrent: true,
1330
+ });
1331
+
1332
+ expect(Scheduler).toFlushAndYield(['Init A', 'Init B', 'Loading...']);
1333
+ expect(root).not.toMatchRenderedOutput('AB');
1334
+
1335
+ await LazyChildA;
1336
+ await LazyChildB;
1337
+
1338
+ expect(Scheduler).toFlushAndYield([
1339
+ 'A',
1340
+ 'B',
1341
+ 'Did mount: A',
1342
+ 'Did mount: B',
1343
+ ]);
1344
+ expect(root).toMatchRenderedOutput('AB');
1345
+
1346
+ // Swap the position of A and B
1347
+ root.update(<Parent swap={true} />);
1348
+ expect(Scheduler).toFlushAndYield(['Init B2', 'Loading...']);
1349
+ jest.runAllTimers();
1350
+
1351
+ // The suspense boundary should've triggered now.
1352
+ expect(root).toMatchRenderedOutput('Loading...');
1353
+ await resolveB2({default: ChildB});
1354
+
1355
+ // We need to flush to trigger the second one to load.
1356
+ expect(Scheduler).toFlushAndYield(['Init A2']);
1357
+ await LazyChildA2;
1358
+
1359
+ expect(Scheduler).toFlushAndYield([
1360
+ 'b',
1361
+ 'a',
1362
+ 'Did update: b',
1363
+ 'Did update: a',
1364
+ ]);
1365
+ expect(root).toMatchRenderedOutput('ba');
1366
+ });
1367
+
1368
+ // @gate enableLazyElements
1369
+ it('mount and reorder lazy types (legacy mode)', async () => {
1370
+ class Child extends React.Component {
1371
+ componentDidMount() {
1372
+ Scheduler.unstable_yieldValue('Did mount: ' + this.props.label);
1373
+ }
1374
+ componentDidUpdate() {
1375
+ Scheduler.unstable_yieldValue('Did update: ' + this.props.label);
1376
+ }
1377
+ render() {
1378
+ return <Text text={this.props.label} />;
1379
+ }
1380
+ }
1381
+
1382
+ function ChildA({lowerCase}) {
1383
+ return <Child label={lowerCase ? 'a' : 'A'} />;
1384
+ }
1385
+
1386
+ function ChildB({lowerCase}) {
1387
+ return <Child label={lowerCase ? 'b' : 'B'} />;
1388
+ }
1389
+
1390
+ const LazyChildA = lazy(() => {
1391
+ Scheduler.unstable_yieldValue('Init A');
1392
+ return fakeImport(ChildA);
1393
+ });
1394
+ const LazyChildB = lazy(() => {
1395
+ Scheduler.unstable_yieldValue('Init B');
1396
+ return fakeImport(ChildB);
1397
+ });
1398
+ const LazyChildA2 = lazy(() => {
1399
+ Scheduler.unstable_yieldValue('Init A2');
1400
+ return fakeImport(ChildA);
1401
+ });
1402
+ const LazyChildB2 = lazy(() => {
1403
+ Scheduler.unstable_yieldValue('Init B2');
1404
+ return fakeImport(ChildB);
1405
+ });
1406
+
1407
+ function Parent({swap}) {
1408
+ return (
1409
+ <Suspense fallback={<Text text="Outer..." />}>
1410
+ <Suspense fallback={<Text text="Loading..." />}>
1411
+ {swap
1412
+ ? [
1413
+ <LazyChildB2 key="B" lowerCase={true} />,
1414
+ <LazyChildA2 key="A" lowerCase={true} />,
1415
+ ]
1416
+ : [<LazyChildA key="A" />, <LazyChildB key="B" />]}
1417
+ </Suspense>
1418
+ </Suspense>
1419
+ );
1420
+ }
1421
+
1422
+ const root = ReactTestRenderer.create(<Parent swap={false} />, {
1423
+ unstable_isConcurrent: false,
1424
+ });
1425
+
1426
+ expect(Scheduler).toHaveYielded(['Init A', 'Init B', 'Loading...']);
1427
+ expect(root).not.toMatchRenderedOutput('AB');
1428
+
1429
+ await LazyChildA;
1430
+ await LazyChildB;
1431
+
1432
+ expect(Scheduler).toFlushAndYield([
1433
+ 'A',
1434
+ 'B',
1435
+ 'Did mount: A',
1436
+ 'Did mount: B',
1437
+ ]);
1438
+ expect(root).toMatchRenderedOutput('AB');
1439
+
1440
+ // Swap the position of A and B
1441
+ root.update(<Parent swap={true} />);
1442
+ expect(Scheduler).toHaveYielded(['Init B2', 'Loading...']);
1443
+ await LazyChildB2;
1444
+ // We need to flush to trigger the second one to load.
1445
+ expect(Scheduler).toFlushAndYield(['Init A2']);
1446
+ await LazyChildA2;
1447
+
1448
+ expect(Scheduler).toFlushAndYield([
1449
+ 'b',
1450
+ 'a',
1451
+ 'Did update: b',
1452
+ 'Did update: a',
1453
+ ]);
1454
+ expect(root).toMatchRenderedOutput('ba');
1455
+ });
1456
+
1457
// @gate enableLazyElements
1458
it('mount and reorder lazy elements', async () => {
1459
class Child extends React.Component {
1529
]);
1530
expect(root).toMatchRenderedOutput('ba');
1531
});
1532
+
1533
+ // @gate enableLazyElements
1534
+ it('mount and reorder lazy elements (legacy mode)', async () => {
1535
+ class Child extends React.Component {
1536
+ componentDidMount() {
1537
+ Scheduler.unstable_yieldValue('Did mount: ' + this.props.label);
1538
+ }
1539
+ componentDidUpdate() {
1540
+ Scheduler.unstable_yieldValue('Did update: ' + this.props.label);
1541
+ }
1542
+ render() {
1543
+ return <Text text={this.props.label} />;
1544
+ }
1545
+ }
1546
+
1547
+ const lazyChildA = lazy(() => {
1548
+ Scheduler.unstable_yieldValue('Init A');
1549
+ return fakeImport(<Child key="A" label="A" />);
1550
+ });
1551
+ const lazyChildB = lazy(() => {
1552
+ Scheduler.unstable_yieldValue('Init B');
1553
+ return fakeImport(<Child key="B" label="B" />);
1554
+ });
1555
+ const lazyChildA2 = lazy(() => {
1556
+ Scheduler.unstable_yieldValue('Init A2');
1557
+ return fakeImport(<Child key="A" label="a" />);
1558
+ });
1559
+ const lazyChildB2 = lazy(() => {
1560
+ Scheduler.unstable_yieldValue('Init B2');
1561
+ return fakeImport(<Child key="B" label="b" />);
1562
+ });
1563
+
1564
+ function Parent({swap}) {
1565
+ return (
1566
+ <Suspense fallback={<Text text="Loading..." />}>
1567
+ {swap ? [lazyChildB2, lazyChildA2] : [lazyChildA, lazyChildB]}
1568
+ </Suspense>
1569
+ );
1570
+ }
1571
+
1572
+ const root = ReactTestRenderer.create(<Parent swap={false} />, {
1573
+ unstable_isConcurrent: false,
1574
+ });
1575
+
1576
+ expect(Scheduler).toHaveYielded(['Init A', 'Loading...']);
1577
+ expect(root).not.toMatchRenderedOutput('AB');
1578
+
1579
+ await lazyChildA;
1580
+ // We need to flush to trigger the B to load.
1581
+ expect(Scheduler).toFlushAndYield(['Init B']);
1582
+ await lazyChildB;
1583
+
1584
+ expect(Scheduler).toFlushAndYield([
1585
+ 'A',
1586
+ 'B',
1587
+ 'Did mount: A',
1588
+ 'Did mount: B',
1589
+ ]);
1590
+ expect(root).toMatchRenderedOutput('AB');
1591
+
1592
+ // Swap the position of A and B
1593
+ root.update(<Parent swap={true} />);
1594
+ expect(Scheduler).toHaveYielded(['Init B2', 'Loading...']);
1595
+ await lazyChildB2;
1596
+ // We need to flush to trigger the second one to load.
1597
+ expect(Scheduler).toFlushAndYield(['Init A2']);
1598
+ await lazyChildA2;
1599
+
1600
+ expect(Scheduler).toFlushAndYield([
1601
+ 'b',
1602
+ 'a',
1603
+ 'Did update: b',
1604
+ 'Did update: a',
1605
+ ]);
1606
+ expect(root).toMatchRenderedOutput('ba');
1607
+ });
1608
});