17
let ReactTestUtils;
18
let Scheduler;
19
let Suspense;
20
-let usePress;
20
21
function dispatchMouseHoverEvent(to, from) {
22
if (!to) {
105
ReactTestUtils = require('react-dom/test-utils');
106
Scheduler = require('scheduler');
107
Suspense = React.Suspense;
109
- usePress = require('react-interactions/events/press').usePress;
108
});
109
110
if (!__EXPERIMENTAL__) {
350
document.body.removeChild(container);
351
});
352
355
- it('hydrates the target boundary synchronously during a click (flare)', async () => {
356
- function Child({text}) {
357
- Scheduler.unstable_yieldValue(text);
358
- const listener = usePress({
359
- onPress() {
360
- Scheduler.unstable_yieldValue('Clicked ' + text);
361
- },
362
- });
353
+ if (__EXPERIMENTAL__) {
354
+ it('hydrates the target boundary synchronously during a click (flare)', async () => {
355
+ let usePress = require('react-interactions/events/press').usePress;
356
364
- return <span DEPRECATED_flareListeners={listener}>{text}</span>;
365
- }
357
+ function Child({text}) {
358
+ Scheduler.unstable_yieldValue(text);
359
+ const listener = usePress({
360
+ onPress() {
361
+ Scheduler.unstable_yieldValue('Clicked ' + text);
362
+ },
363
+ });
364
367
- function App() {
368
- Scheduler.unstable_yieldValue('App');
369
- return (
370
- <div>
371
- <Suspense fallback="Loading...">
372
- <Child text="A" />
373
- </Suspense>
374
- <Suspense fallback="Loading...">
375
- <Child text="B" />
376
- </Suspense>
377
- </div>
378
- );
379
- }
365
+ return <span DEPRECATED_flareListeners={listener}>{text}</span>;
366
+ }
367
381
- let finalHTML = ReactDOMServer.renderToString(<App />);
368
+ function App() {
369
+ Scheduler.unstable_yieldValue('App');
370
+ return (
371
+ <div>
372
+ <Suspense fallback="Loading...">
373
+ <Child text="A" />
374
+ </Suspense>
375
+ <Suspense fallback="Loading...">
376
+ <Child text="B" />
377
+ </Suspense>
378
+ </div>
379
+ );
380
+ }
381
383
- expect(Scheduler).toHaveYielded(['App', 'A', 'B']);
382
+ let finalHTML = ReactDOMServer.renderToString(<App />);
383
385
- let container = document.createElement('div');
386
- // We need this to be in the document since we'll dispatch events on it.
387
- document.body.appendChild(container);
384
+ expect(Scheduler).toHaveYielded(['App', 'A', 'B']);
385
389
- container.innerHTML = finalHTML;
386
+ let container = document.createElement('div');
387
+ // We need this to be in the document since we'll dispatch events on it.
388
+ document.body.appendChild(container);
389
391
- let root = ReactDOM.createRoot(container, {hydrate: true});
392
- root.render(<App />);
390
+ container.innerHTML = finalHTML;
391
394
- // Nothing has been hydrated so far.
395
- expect(Scheduler).toHaveYielded([]);
392
+ let root = ReactDOM.createRoot(container, {hydrate: true});
393
+ root.render(<App />);
394
397
- let span = container.getElementsByTagName('span')[1];
395
+ // Nothing has been hydrated so far.
396
+ expect(Scheduler).toHaveYielded([]);
397
399
- let target = createEventTarget(span);
398
+ let span = container.getElementsByTagName('span')[1];
399
401
- // This should synchronously hydrate the root App and the second suspense
402
- // boundary.
403
- let preventDefault = jest.fn();
404
- target.virtualclick({preventDefault});
400
+ let target = createEventTarget(span);
401
406
- // The event should have been canceled because we called preventDefault.
407
- expect(preventDefault).toHaveBeenCalled();
402
+ // This should synchronously hydrate the root App and the second suspense
403
+ // boundary.
404
+ let preventDefault = jest.fn();
405
+ target.virtualclick({preventDefault});
406
409
- // We rendered App, B and then invoked the event without rendering A.
410
- expect(Scheduler).toHaveYielded(['App', 'B', 'Clicked B']);
407
+ // The event should have been canceled because we called preventDefault.
408
+ expect(preventDefault).toHaveBeenCalled();
409
412
- // After continuing the scheduler, we finally hydrate A.
413
- expect(Scheduler).toFlushAndYield(['A']);
410
+ // We rendered App, B and then invoked the event without rendering A.
411
+ expect(Scheduler).toHaveYielded(['App', 'B', 'Clicked B']);
412
415
- document.body.removeChild(container);
416
- });
413
+ // After continuing the scheduler, we finally hydrate A.
414
+ expect(Scheduler).toFlushAndYield(['A']);
415
418
- it('hydrates at higher pri if sync did not work first time (flare)', async () => {
419
- let suspend = false;
420
- let resolve;
421
- let promise = new Promise(resolvePromise => (resolve = resolvePromise));
416
+ document.body.removeChild(container);
417
+ });
418
423
- function Child({text}) {
424
- if ((text === 'A' || text === 'D') && suspend) {
425
- throw promise;
419
+ it('hydrates at higher pri if sync did not work first time (flare)', async () => {
420
+ let usePress = require('react-interactions/events/press').usePress;
421
+ let suspend = false;
422
+ let resolve;
423
+ let promise = new Promise(resolvePromise => (resolve = resolvePromise));
424
+
425
+ function Child({text}) {
426
+ if ((text === 'A' || text === 'D') && suspend) {
427
+ throw promise;
428
+ }
429
+ Scheduler.unstable_yieldValue(text);
430
+
431
+ const listener = usePress({
432
+ onPress() {
433
+ Scheduler.unstable_yieldValue('Clicked ' + text);
434
+ },
435
+ });
436
+ return <span DEPRECATED_flareListeners={listener}>{text}</span>;
437
}
427
- Scheduler.unstable_yieldValue(text);
438
429
- const listener = usePress({
430
- onPress() {
431
- Scheduler.unstable_yieldValue('Clicked ' + text);
432
- },
433
- });
434
- return <span DEPRECATED_flareListeners={listener}>{text}</span>;
435
- }
439
+ function App() {
440
+ Scheduler.unstable_yieldValue('App');
441
+ return (
442
+ <div>
443
+ <Suspense fallback="Loading...">
444
+ <Child text="A" />
445
+ </Suspense>
446
+ <Suspense fallback="Loading...">
447
+ <Child text="B" />
448
+ </Suspense>
449
+ <Suspense fallback="Loading...">
450
+ <Child text="C" />
451
+ </Suspense>
452
+ <Suspense fallback="Loading...">
453
+ <Child text="D" />
454
+ </Suspense>
455
+ </div>
456
+ );
457
+ }
458
437
- function App() {
438
- Scheduler.unstable_yieldValue('App');
439
- return (
440
- <div>
441
- <Suspense fallback="Loading...">
442
- <Child text="A" />
443
- </Suspense>
444
- <Suspense fallback="Loading...">
445
- <Child text="B" />
446
- </Suspense>
447
- <Suspense fallback="Loading...">
448
- <Child text="C" />
449
- </Suspense>
450
- <Suspense fallback="Loading...">
451
- <Child text="D" />
452
- </Suspense>
453
- </div>
454
- );
455
- }
459
+ let finalHTML = ReactDOMServer.renderToString(<App />);
460
457
- let finalHTML = ReactDOMServer.renderToString(<App />);
461
+ expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
462
459
- expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
463
+ let container = document.createElement('div');
464
+ // We need this to be in the document since we'll dispatch events on it.
465
+ document.body.appendChild(container);
466
461
- let container = document.createElement('div');
462
- // We need this to be in the document since we'll dispatch events on it.
463
- document.body.appendChild(container);
467
+ container.innerHTML = finalHTML;
468
465
- container.innerHTML = finalHTML;
469
+ let spanD = container.getElementsByTagName('span')[3];
470
467
- let spanD = container.getElementsByTagName('span')[3];
471
+ suspend = true;
472
469
- suspend = true;
473
+ // A and D will be suspended. We'll click on D which should take
474
+ // priority, after we unsuspend.
475
+ let root = ReactDOM.createRoot(container, {hydrate: true});
476
+ root.render(<App />);
477
471
- // A and D will be suspended. We'll click on D which should take
472
- // priority, after we unsuspend.
473
- let root = ReactDOM.createRoot(container, {hydrate: true});
474
- root.render(<App />);
478
+ // Nothing has been hydrated so far.
479
+ expect(Scheduler).toHaveYielded([]);
480
476
- // Nothing has been hydrated so far.
477
- expect(Scheduler).toHaveYielded([]);
481
+ // This click target cannot be hydrated yet because it's suspended.
482
+ let result = dispatchClickEvent(spanD);
483
479
- // This click target cannot be hydrated yet because it's suspended.
480
- let result = dispatchClickEvent(spanD);
484
+ expect(Scheduler).toHaveYielded(['App']);
485
482
- expect(Scheduler).toHaveYielded(['App']);
486
+ expect(result).toBe(true);
487
484
- expect(result).toBe(true);
488
+ // Continuing rendering will render B next.
489
+ expect(Scheduler).toFlushAndYield(['B', 'C']);
490
486
- // Continuing rendering will render B next.
487
- expect(Scheduler).toFlushAndYield(['B', 'C']);
491
+ suspend = false;
492
+ resolve();
493
+ await promise;
494
489
- suspend = false;
490
- resolve();
491
- await promise;
495
+ // After the click, we should prioritize D and the Click first,
496
+ // and only after that render A and C.
497
+ expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
498
493
- // After the click, we should prioritize D and the Click first,
494
- // and only after that render A and C.
495
- expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
499
+ document.body.removeChild(container);
500
+ });
501
497
- document.body.removeChild(container);
498
- });
502
+ it('hydrates at higher pri for secondary discrete events (flare)', async () => {
503
+ let usePress = require('react-interactions/events/press').usePress;
504
+ let suspend = false;
505
+ let resolve;
506
+ let promise = new Promise(resolvePromise => (resolve = resolvePromise));
507
500
- it('hydrates at higher pri for secondary discrete events (flare)', async () => {
501
- let suspend = false;
502
- let resolve;
503
- let promise = new Promise(resolvePromise => (resolve = resolvePromise));
508
+ function Child({text}) {
509
+ if ((text === 'A' || text === 'D') && suspend) {
510
+ throw promise;
511
+ }
512
+ Scheduler.unstable_yieldValue(text);
513
505
- function Child({text}) {
506
- if ((text === 'A' || text === 'D') && suspend) {
507
- throw promise;
514
+ const listener = usePress({
515
+ onPress() {
516
+ Scheduler.unstable_yieldValue('Clicked ' + text);
517
+ },
518
+ });
519
+ return <span DEPRECATED_flareListeners={listener}>{text}</span>;
520
}
509
- Scheduler.unstable_yieldValue(text);
521
511
- const listener = usePress({
512
- onPress() {
513
- Scheduler.unstable_yieldValue('Clicked ' + text);
514
- },
515
- });
516
- return <span DEPRECATED_flareListeners={listener}>{text}</span>;
517
- }
522
+ function App() {
523
+ Scheduler.unstable_yieldValue('App');
524
+ return (
525
+ <div>
526
+ <Suspense fallback="Loading...">
527
+ <Child text="A" />
528
+ </Suspense>
529
+ <Suspense fallback="Loading...">
530
+ <Child text="B" />
531
+ </Suspense>
532
+ <Suspense fallback="Loading...">
533
+ <Child text="C" />
534
+ </Suspense>
535
+ <Suspense fallback="Loading...">
536
+ <Child text="D" />
537
+ </Suspense>
538
+ </div>
539
+ );
540
+ }
541
519
- function App() {
520
- Scheduler.unstable_yieldValue('App');
521
- return (
522
- <div>
523
- <Suspense fallback="Loading...">
524
- <Child text="A" />
525
- </Suspense>
526
- <Suspense fallback="Loading...">
527
- <Child text="B" />
528
- </Suspense>
529
- <Suspense fallback="Loading...">
530
- <Child text="C" />
531
- </Suspense>
532
- <Suspense fallback="Loading...">
533
- <Child text="D" />
534
- </Suspense>
535
- </div>
536
- );
537
- }
542
+ let finalHTML = ReactDOMServer.renderToString(<App />);
543
539
- let finalHTML = ReactDOMServer.renderToString(<App />);
544
+ expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
545
541
- expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
546
+ let container = document.createElement('div');
547
+ // We need this to be in the document since we'll dispatch events on it.
548
+ document.body.appendChild(container);
549
543
- let container = document.createElement('div');
544
- // We need this to be in the document since we'll dispatch events on it.
545
- document.body.appendChild(container);
550
+ container.innerHTML = finalHTML;
551
547
- container.innerHTML = finalHTML;
552
+ let spanA = container.getElementsByTagName('span')[0];
553
+ let spanC = container.getElementsByTagName('span')[2];
554
+ let spanD = container.getElementsByTagName('span')[3];
555
549
- let spanA = container.getElementsByTagName('span')[0];
550
- let spanC = container.getElementsByTagName('span')[2];
551
- let spanD = container.getElementsByTagName('span')[3];
556
+ suspend = true;
557
553
- suspend = true;
558
+ // A and D will be suspended. We'll click on D which should take
559
+ // priority, after we unsuspend.
560
+ let root = ReactDOM.createRoot(container, {hydrate: true});
561
+ root.render(<App />);
562
555
- // A and D will be suspended. We'll click on D which should take
556
- // priority, after we unsuspend.
557
- let root = ReactDOM.createRoot(container, {hydrate: true});
558
- root.render(<App />);
563
+ // Nothing has been hydrated so far.
564
+ expect(Scheduler).toHaveYielded([]);
565
560
- // Nothing has been hydrated so far.
561
- expect(Scheduler).toHaveYielded([]);
566
+ // This click target cannot be hydrated yet because the first is Suspended.
567
+ dispatchClickEvent(spanA);
568
+ dispatchClickEvent(spanC);
569
+ dispatchClickEvent(spanD);
570
563
- // This click target cannot be hydrated yet because the first is Suspended.
564
- dispatchClickEvent(spanA);
565
- dispatchClickEvent(spanC);
566
- dispatchClickEvent(spanD);
571
+ expect(Scheduler).toHaveYielded(['App']);
572
568
- expect(Scheduler).toHaveYielded(['App']);
573
+ suspend = false;
574
+ resolve();
575
+ await promise;
576
570
- suspend = false;
571
- resolve();
572
- await promise;
573
-
574
- // We should prioritize hydrating A, C and D first since we clicked in
575
- // them. Only after they're done will we hydrate B.
576
- expect(Scheduler).toFlushAndYield([
577
- 'A',
578
- 'Clicked A',
579
- 'C',
580
- 'Clicked C',
581
- 'D',
582
- 'Clicked D',
583
- // B should render last since it wasn't clicked.
584
- 'B',
585
- ]);
577
+ // We should prioritize hydrating A, C and D first since we clicked in
578
+ // them. Only after they're done will we hydrate B.
579
+ expect(Scheduler).toFlushAndYield([
580
+ 'A',
581
+ 'Clicked A',
582
+ 'C',
583
+ 'Clicked C',
584
+ 'D',
585
+ 'Clicked D',
586
+ // B should render last since it wasn't clicked.
587
+ 'B',
588
+ ]);
589
587
- document.body.removeChild(container);
588
- });
590
+ document.body.removeChild(container);
591
+ });
592
+ }
593
594
it('hydrates the hovered targets as higher priority for continuous events', async () => {
595
let suspend = false;