9
10
'use strict';
11
12
-import {insertNodesAndExecuteScripts} from '../test-utils/FizzTestUtils';
12
+import {
13
+ insertNodesAndExecuteScripts,
14
+ getVisibleChildren,
15
+} from '../test-utils/FizzTestUtils';
16
17
// Polyfills for test environment
18
global.ReadableStream =
20
global.TextEncoder = require('util').TextEncoder;
21
22
let act;
23
+let assertLog;
24
+let waitForPaint;
25
let container;
26
let React;
27
+let Scheduler;
28
let ReactDOMServer;
29
let ReactDOMClient;
30
let useDeferredValue;
31
+let Suspense;
32
33
describe('ReactDOMFizzForm', () => {
34
beforeEach(() => {
35
jest.resetModules();
36
React = require('react');
37
+ Scheduler = require('scheduler');
38
ReactDOMServer = require('react-dom/server.browser');
39
ReactDOMClient = require('react-dom/client');
32
- useDeferredValue = require('react').useDeferredValue;
40
+ useDeferredValue = React.useDeferredValue;
41
+ Suspense = React.Suspense;
42
act = require('internal-test-utils').act;
43
+ assertLog = require('internal-test-utils').assertLog;
44
+ waitForPaint = require('internal-test-utils').waitForPaint;
45
container = document.createElement('div');
46
document.body.appendChild(container);
47
});
65
insertNodesAndExecuteScripts(temp, container, null);
66
}
67
68
+ function Text({text}) {
69
+ Scheduler.log(text);
70
+ return text;
71
+ }
72
+
73
// @gate enableUseDeferredValueInitialArg
74
it('returns initialValue argument, if provided', async () => {
75
function App() {
84
await act(() => ReactDOMClient.hydrateRoot(container, <App />));
85
expect(container.textContent).toEqual('Final');
86
});
87
+
88
+ // @gate enableUseDeferredValueInitialArg
89
+ it(
90
+ 'useDeferredValue during hydration has higher priority than remaining ' +
91
+ 'incremental hydration',
92
+ async () => {
93
+ function B() {
94
+ const text = useDeferredValue('B [Final]', 'B [Initial]');
95
+ return <Text text={text} />;
96
+ }
97
+
98
+ function App() {
99
+ return (
100
+ <div>
101
+ <span>
102
+ <Text text="A" />
103
+ </span>
104
+ <Suspense fallback={<Text text="Loading..." />}>
105
+ <span>
106
+ <B />
107
+ </span>
108
+ <div>
109
+ <Suspense fallback={<Text text="Loading..." />}>
110
+ <span id="C" ref={cRef}>
111
+ <Text text="C" />
112
+ </span>
113
+ </Suspense>
114
+ </div>
115
+ </Suspense>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ const cRef = React.createRef();
121
+
122
+ // The server renders using the "initial" value for B.
123
+ const stream = await ReactDOMServer.renderToReadableStream(<App />);
124
+ await readIntoContainer(stream);
125
+ assertLog(['A', 'B [Initial]', 'C']);
126
+ expect(getVisibleChildren(container)).toEqual(
127
+ <div>
128
+ <span>A</span>
129
+ <span>B [Initial]</span>
130
+ <div>
131
+ <span id="C">C</span>
132
+ </div>
133
+ </div>,
134
+ );
135
+
136
+ const serverRenderedC = document.getElementById('C');
137
+
138
+ // On the client, we first hydrate the initial value, then upgrade
139
+ // to final.
140
+ await act(async () => {
141
+ ReactDOMClient.hydrateRoot(container, <App />);
142
+
143
+ // First the outermost Suspense boundary hydrates.
144
+ await waitForPaint(['A']);
145
+ expect(cRef.current).toBe(null);
146
+
147
+ // Then the next level hydrates. This level includes a useDeferredValue,
148
+ // so we should prioritize upgrading it before we proceed to hydrating
149
+ // additional levels.
150
+ await waitForPaint(['B [Initial]']);
151
+ expect(getVisibleChildren(container)).toEqual(
152
+ <div>
153
+ <span>A</span>
154
+ <span>B [Initial]</span>
155
+ <div>
156
+ <span id="C">C</span>
157
+ </div>
158
+ </div>,
159
+ );
160
+ expect(cRef.current).toBe(null);
161
+
162
+ // This paint should only update B. C should still be dehydrated.
163
+ await waitForPaint(['B [Final]']);
164
+ expect(getVisibleChildren(container)).toEqual(
165
+ <div>
166
+ <span>A</span>
167
+ <span>B [Final]</span>
168
+ <div>
169
+ <span id="C">C</span>
170
+ </div>
171
+ </div>,
172
+ );
173
+ expect(cRef.current).toBe(null);
174
+ });
175
+ // Finally we can hydrate C
176
+ assertLog(['C']);
177
+ expect(getVisibleChildren(container)).toEqual(
178
+ <div>
179
+ <span>A</span>
180
+ <span>B [Final]</span>
181
+ <div>
182
+ <span id="C">C</span>
183
+ </div>
184
+ </div>,
185
+ );
186
+ expect(cRef.current).toBe(serverRenderedC);
187
+ },
188
+ );
189
});