1
+let React;
2
+let ReactFeatureFlags;
3
+let ReactNoop;
4
+let Scheduler;
5
+let Suspense;
6
+let scheduleCallback;
7
+let NormalPriority;
8
+
9
+describe('ReactSuspenseList', () => {
10
+ beforeEach(() => {
11
+ jest.resetModules();
12
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
13
+ ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
14
+ ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
15
+ ReactFeatureFlags.disableSchedulerTimeoutBasedOnReactExpirationTime = true;
16
+ React = require('react');
17
+ ReactNoop = require('react-noop-renderer');
18
+ Scheduler = require('scheduler');
19
+ Suspense = React.Suspense;
20
+
21
+ scheduleCallback = Scheduler.unstable_scheduleCallback;
22
+ NormalPriority = Scheduler.unstable_NormalPriority;
23
+ });
24
+
25
+ function Text(props) {
26
+ Scheduler.unstable_yieldValue(props.text);
27
+ return props.text;
28
+ }
29
+
30
+ function createAsyncText(text) {
31
+ let resolved = false;
32
+ let Component = function() {
33
+ if (!resolved) {
34
+ Scheduler.unstable_yieldValue('Suspend! [' + text + ']');
35
+ throw promise;
36
+ }
37
+ return <Text text={text} />;
38
+ };
39
+ let promise = new Promise(resolve => {
40
+ Component.resolve = function() {
41
+ resolved = true;
42
+ return resolve();
43
+ };
44
+ });
45
+ return Component;
46
+ }
47
+
48
+ it('appends rendering tasks to the end of the priority queue', async () => {
49
+ const A = createAsyncText('A');
50
+ const B = createAsyncText('B');
51
+
52
+ function App({show}) {
53
+ return (
54
+ <Suspense fallback={<Text text="Loading..." />}>
55
+ {show ? <A /> : null}
56
+ {show ? <B /> : null}
57
+ </Suspense>
58
+ );
59
+ }
60
+
61
+ const root = ReactNoop.createRoot(null);
62
+
63
+ root.render(<App show={false} />);
64
+ expect(Scheduler).toFlushAndYield([]);
65
+
66
+ root.render(<App show={true} />);
67
+ expect(Scheduler).toFlushAndYield([
68
+ 'Suspend! [A]',
69
+ 'Suspend! [B]',
70
+ 'Loading...',
71
+ ]);
72
+ expect(root).toMatchRenderedOutput(null);
73
+
74
+ Scheduler.unstable_advanceTime(2000);
75
+ expect(root).toMatchRenderedOutput(null);
76
+
77
+ scheduleCallback(NormalPriority, () => {
78
+ Scheduler.unstable_yieldValue('Resolve A');
79
+ A.resolve();
80
+ });
81
+ scheduleCallback(NormalPriority, () => {
82
+ Scheduler.unstable_yieldValue('Resolve B');
83
+ B.resolve();
84
+ });
85
+
86
+ // This resolves A and schedules a task for React to retry.
87
+ await expect(Scheduler).toFlushAndYieldThrough(['Resolve A']);
88
+
89
+ // The next task that flushes should be the one that resolves B. The render
90
+ // task should not jump the queue ahead of B.
91
+ await expect(Scheduler).toFlushAndYieldThrough(['Resolve B']);
92
+
93
+ expect(Scheduler).toFlushAndYield(['A', 'B']);
94
+ expect(root).toMatchRenderedOutput('AB');
95
+ });
96
+});