Add back accidentally deleted test comments (#26294)
The codemod I used in #26288 accidentally caused some comments to be deleted. Because not all affected lines included comments, I didn't notice until after landing. This adds the comments back.
Andrew Clark committed
Mar 3, 2023 at 14:34 UTC
5c633a48f9bdc212e27ae026c74148b42cc47efb
9 files changed
+124
packages/react-reconciler/src/__tests__/ReactBatching-test.internal.js
+2
@@ -166,9 +166,11 @@ describe('ReactBlockingMode', () => {
166
assertLog(['A1', 'B1']);
167
expect(root).toMatchRenderedOutput('A1B1');
168
} else {
169
+ // Only the second update should have flushed synchronously
170
assertLog(['B1']);
171
expect(root).toMatchRenderedOutput('A0B1');
172
173
+ // Now flush the first update
174
await waitForAll(['A1']);
175
expect(root).toMatchRenderedOutput('A1B1');
176
}
packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js
+5
@@ -143,6 +143,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
143
</>,
144
);
145
});
146
+ // Inner contents finish in separate commit from outer
147
assertLog(['Inner']);
148
expect(root).toMatchRenderedOutput(
149
<>
@@ -178,6 +179,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
179
await act(async () => {
180
root.render(<App />);
181
});
182
+ // Inner contents finish in separate commit from outer
183
assertLog(['Outer', 'Loading...', 'Inner [0]']);
184
expect(root).toMatchRenderedOutput(
185
<>
@@ -190,6 +192,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
192
await act(async () => {
193
setCount(1);
194
});
195
+ // Entire update finishes in a single commit
196
assertLog(['Outer', 'Inner [1]']);
197
expect(root).toMatchRenderedOutput(
198
<>
@@ -227,6 +230,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
230
</>,
231
);
232
});
233
+ // Inner contents suspended, so we continue showing a fallback.
234
assertLog(['Suspend! [Inner]']);
235
expect(root).toMatchRenderedOutput(
236
<>
@@ -276,6 +280,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
280
await act(async () => {
281
root.render(<App />);
282
});
283
+ // Each level commits separately
284
assertLog(['A', 'Loading B...', 'B', 'Loading C...', 'C']);
285
expect(root).toMatchRenderedOutput(
286
<>
packages/react-reconciler/src/__tests__/ReactCache-test.js
+31
@@ -219,6 +219,7 @@ describe('ReactCache', () => {
219
await act(async () => {
220
root.render('Bye');
221
});
222
+ // no cleanup: cache is still retained at the root
223
assertLog([]);
224
expect(root).toMatchRenderedOutput('Bye');
225
});
@@ -245,6 +246,7 @@ describe('ReactCache', () => {
246
await act(async () => {
247
root.render('Bye');
248
});
249
+ // no cleanup: cache is still retained at the root
250
assertLog([]);
251
expect(root).toMatchRenderedOutput('Bye');
252
});
@@ -273,6 +275,8 @@ describe('ReactCache', () => {
275
root.render(<App showMore={false} />);
276
});
277
278
+ // Even though there are two new <Cache /> trees, they should share the same
279
+ // data cache. So there should be only a single cache miss for A.
280
assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
281
expect(root).toMatchRenderedOutput('Loading...Loading...');
282
@@ -285,6 +289,7 @@ describe('ReactCache', () => {
289
await act(async () => {
290
root.render('Bye');
291
});
292
+ // no cleanup: cache is still retained at the root
293
assertLog([]);
294
expect(root).toMatchRenderedOutput('Bye');
295
});
@@ -320,6 +325,8 @@ describe('ReactCache', () => {
325
await act(async () => {
326
root.render(<App showMore={true} />);
327
});
328
+ // Even though there are two new <Cache /> trees, they should share the same
329
+ // data cache. So there should be only a single cache miss for A.
330
assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
331
expect(root).toMatchRenderedOutput('Loading...Loading...');
332
@@ -332,6 +339,9 @@ describe('ReactCache', () => {
339
await act(async () => {
340
root.render('Bye');
341
});
342
+ // cleanup occurs for the cache shared by the inner cache boundaries (which
343
+ // are not shared w the root because they were added in an update)
344
+ // note that no cache is created for the root since the cache is never accessed
345
assertLog(['Cache cleanup: A [v1]']);
346
expect(root).toMatchRenderedOutput('Bye');
347
});
@@ -356,6 +366,8 @@ describe('ReactCache', () => {
366
await act(async () => {
367
root.render(<App />);
368
});
369
+ // Even though there is a nested <Cache /> boundary, it should share the same
370
+ // data cache as the root. So there should be only a single cache miss for A.
371
assertLog(['Cache miss! [A]', 'Loading...']);
372
expect(root).toMatchRenderedOutput('Loading...');
373
@@ -368,6 +380,7 @@ describe('ReactCache', () => {
380
await act(async () => {
381
root.render('Bye');
382
});
383
+ // no cleanup: cache is still retained at the root
384
assertLog([]);
385
expect(root).toMatchRenderedOutput('Bye');
386
},
@@ -412,6 +425,7 @@ describe('ReactCache', () => {
425
await act(async () => {
426
root.render('Bye');
427
});
428
+ // no cleanup: cache is still retained at the root
429
assertLog([]);
430
expect(root).toMatchRenderedOutput('Bye');
431
});
@@ -468,6 +482,8 @@ describe('ReactCache', () => {
482
await act(async () => {
483
root.render('Bye!');
484
});
485
+ // Cleanup occurs for the *second* cache instance: the first is still
486
+ // referenced by the root
487
assertLog(['Cache cleanup: A [v2]']);
488
expect(root).toMatchRenderedOutput('Bye!');
489
});
@@ -549,6 +565,7 @@ describe('ReactCache', () => {
565
await act(async () => {
566
root.render('Bye');
567
});
568
+ // no cleanup: cache is still retained at the root
569
assertLog([]);
570
expect(root).toMatchRenderedOutput('Bye');
571
});
@@ -728,12 +745,14 @@ describe('ReactCache', () => {
745
await act(async () => {
746
resolveMostRecentTextCache('A');
747
});
748
+ // Note that the version has updated, and the previous cache is cleared
749
assertLog(['A [v2]', 'Cache cleanup: A [v1]']);
750
expect(root).toMatchRenderedOutput('A [v2]');
751
752
await act(async () => {
753
root.render('Bye');
754
});
755
+ // the original root cache already cleaned up when the refresh completed
756
assertLog([]);
757
expect(root).toMatchRenderedOutput('Bye');
758
});
@@ -781,12 +800,14 @@ describe('ReactCache', () => {
800
await act(async () => {
801
resolveMostRecentTextCache('A');
802
});
803
+ // Note that the version has updated, and the previous cache is cleared
804
assertLog(['A [v2]']);
805
expect(root).toMatchRenderedOutput('A [v2]');
806
807
await act(async () => {
808
root.render('Bye');
809
});
810
+ // the original root cache already cleaned up when the refresh completed
811
assertLog([]);
812
expect(root).toMatchRenderedOutput('Bye');
813
});
@@ -841,12 +862,15 @@ describe('ReactCache', () => {
862
}),
863
);
864
});
865
+ // The root should re-render without a cache miss.
866
+ // The cache is not cleared up yet, since it's still reference by the root
867
assertLog(['A [v2]']);
868
expect(root).toMatchRenderedOutput('A [v2]');
869
870
await act(async () => {
871
root.render('Bye');
872
});
873
+ // the refreshed cache boundary is unmounted and cleans up
874
assertLog(['Cache cleanup: A [v2]']);
875
expect(root).toMatchRenderedOutput('Bye');
876
});
@@ -920,6 +944,8 @@ describe('ReactCache', () => {
944
await act(async () => {
945
root.render('Bye!');
946
});
947
+ // Unmounting children releases the refreshed cache instance only; the root
948
+ // still retains the original cache instance used for the first render
949
assertLog(['Cache cleanup: A [v3]']);
950
expect(root).toMatchRenderedOutput('Bye!');
951
});
@@ -967,6 +993,8 @@ describe('ReactCache', () => {
993
root.render(<App showMore={true} />);
994
});
995
996
+ // Even though there are two new <Cache /> trees, they should share the same
997
+ // data cache. So there should be only a single cache miss for A.
998
assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
999
expect(root).toMatchRenderedOutput('Loading...Loading...');
1000
@@ -1064,6 +1092,9 @@ describe('ReactCache', () => {
1092
await act(async () => {
1093
root.render('Bye!');
1094
});
1095
+ // Unmounting children releases both cache boundaries, but the original
1096
+ // cache instance (used by second boundary) is still referenced by the root.
1097
+ // only the second cache instance is freed.
1098
assertLog(['Cache cleanup: A [v2]']);
1099
expect(root).toMatchRenderedOutput('Bye!');
1100
},
packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js
+5
@@ -339,6 +339,11 @@ describe('ReactLazyContextPropagation', () => {
339
setOtherValue(1);
340
setOtherValue(0);
341
});
342
+ // NOTE: If this didn't yield anything, that indicates that we never visited
343
+ // the consumer during the render phase, which probably means the eager
344
+ // bailout mechanism kicked in. Because we're testing the _lazy_ bailout
345
+ // mechanism, update this test to foil the _eager_ bailout, somehow. Perhaps
346
+ // by switching to useReducer.
347
assertLog(['Consumer']);
348
expect(root).toMatchRenderedOutput('0');
349
});
packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js
+9
@@ -78,6 +78,7 @@ describe('ReactDeferredValue', () => {
78
root.render(<App value={2} />);
79
80
await waitForPaint(['Original: 2']);
81
+ // The deferred value updates in a separate render
82
await waitForPaint(['Deferred: 2']);
83
});
84
expect(root).toMatchRenderedOutput(
@@ -92,6 +93,7 @@ describe('ReactDeferredValue', () => {
93
startTransition(() => {
94
root.render(<App value={3} />);
95
});
96
+ // The deferred value updates in the same render as the original
97
await waitForPaint(['Original: 3', 'Deferred: 3']);
98
});
99
expect(root).toMatchRenderedOutput(
@@ -137,6 +139,7 @@ describe('ReactDeferredValue', () => {
139
root.render(<App value={2} />);
140
141
await waitForPaint(['Original: 2']);
142
+ // The deferred value updates in a separate render
143
await waitForPaint(['Deferred: 2']);
144
});
145
expect(root).toMatchRenderedOutput(
@@ -151,6 +154,7 @@ describe('ReactDeferredValue', () => {
154
startTransition(() => {
155
root.render(<App value={3} />);
156
});
157
+ // The deferred value updates in the same render as the original
158
await waitForPaint(['Original: 3', 'Deferred: 3']);
159
});
160
expect(root).toMatchRenderedOutput(
@@ -201,6 +205,7 @@ describe('ReactDeferredValue', () => {
205
root.render(<App value={2} />);
206
207
await waitForPaint(['Original: 2']);
208
+ // The deferred value updates in a separate render
209
await waitForPaint(['Deferred: 2']);
210
});
211
expect(root).toMatchRenderedOutput(
@@ -215,6 +220,7 @@ describe('ReactDeferredValue', () => {
220
startTransition(() => {
221
root.render(<App value={3} />);
222
});
223
+ // The deferred value updates in the same render as the original
224
await waitForPaint(['Original: 3', 'Deferred: 3']);
225
});
226
expect(root).toMatchRenderedOutput(
@@ -270,6 +276,9 @@ describe('ReactDeferredValue', () => {
276
startTransition(() => {
277
root.render(<App value={2} />);
278
});
279
+ // In the regression, the memoized value was not updated during non-urgent
280
+ // updates, so this would flip the deferred value back to the initial
281
+ // value (1) instead of reusing the current one (2).
282
await waitForPaint(['Original: 2', 'Deferred: 2']);
283
expect(root).toMatchRenderedOutput(
284
<div>
packages/react-reconciler/src/__tests__/ReactExpiration-test.js
+14
@@ -171,14 +171,17 @@ describe('ReactExpiration', () => {
171
});
172
// Advance the timer.
173
Scheduler.unstable_advanceTime(2000);
174
+ // Partially flush the first update, then interrupt it.
175
await waitFor(['A [render]']);
176
interrupt();
177
178
+ // Don't advance time by enough to expire the first update.
179
assertLog([]);
180
expect(ReactNoop).toMatchRenderedOutput(null);
181
182
// Schedule another update.
183
ReactNoop.render(<TextClass text="B" />);
184
+ // Both updates are batched
185
await waitForAll(['B [render]', 'B [commit]']);
186
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
187
@@ -190,6 +193,8 @@ describe('ReactExpiration', () => {
193
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
194
// Schedule another update.
195
ReactNoop.render(<TextClass text="B" />);
196
+ // The updates should flush in the same batch, since as far as the scheduler
197
+ // knows, they may have occurred inside the same event.
198
await waitForAll(['B [render]', 'B [commit]']);
199
});
200
@@ -223,14 +228,17 @@ describe('ReactExpiration', () => {
228
});
229
// Advance the timer.
230
Scheduler.unstable_advanceTime(2000);
231
+ // Partially flush the first update, then interrupt it.
232
await waitFor(['A [render]']);
233
interrupt();
234
235
+ // Don't advance time by enough to expire the first update.
236
assertLog([]);
237
expect(ReactNoop).toMatchRenderedOutput(null);
238
239
// Schedule another update.
240
ReactNoop.render(<TextClass text="B" />);
241
+ // Both updates are batched
242
await waitForAll(['B [render]', 'B [commit]']);
243
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
244
@@ -247,6 +255,8 @@ describe('ReactExpiration', () => {
255
256
// Schedule another update.
257
ReactNoop.render(<TextClass text="B" />);
258
+ // The updates should flush in the same batch, since as far as the scheduler
259
+ // knows, they may have occurred inside the same event.
260
await waitForAll(['B [render]', 'B [commit]']);
261
},
262
);
@@ -471,7 +481,9 @@ describe('ReactExpiration', () => {
481
// In other words, we can flush just the first child without flushing
482
// the rest.
483
Scheduler.unstable_flushNumberOfYields(1);
484
+ // Yield right after first child.
485
assertLog(['Sync pri: 1']);
486
+ // Now do the rest.
487
await waitForAll(['Normal pri: 1']);
488
});
489
expect(root).toMatchRenderedOutput('Sync pri: 1, Normal pri: 1');
@@ -533,6 +545,7 @@ describe('ReactExpiration', () => {
545
await waitFor(['Sync pri: 0']);
546
updateSyncPri();
547
});
548
+ // Same thing should happen as last time
549
assertLog([
550
// Interrupt idle update to render sync update
551
'Sync pri: 1',
@@ -733,6 +746,7 @@ describe('ReactExpiration', () => {
746
Scheduler.unstable_flushNumberOfYields(1);
747
assertLog(['A1', 'B1', 'C1']);
748
});
749
+ // The effect flushes after paint.
750
assertLog(['Effect: 1']);
751
});
752
});
packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
+8
@@ -52,6 +52,7 @@ describe('ReactFlushSync', () => {
52
React.startTransition(() => {
53
root.render(<App />);
54
});
55
+ // This will yield right before the passive effect fires
56
await waitForPaint(['0, 0']);
57
58
// The passive effect will schedule a sync update and a normal update.
@@ -67,6 +68,7 @@ describe('ReactFlushSync', () => {
68
if (gate(flags => flags.enableUnifiedSyncLane)) {
69
await waitForPaint([]);
70
} else {
71
+ // Now flush it.
72
await waitForPaint(['1, 1']);
73
}
74
});
@@ -112,9 +114,11 @@ describe('ReactFlushSync', () => {
114
});
115
});
116
});
117
+ // Only the sync update should have flushed
118
assertLog(['1, 0']);
119
expect(root).toMatchRenderedOutput('1, 0');
120
});
121
+ // Now the async update has flushed, too.
122
assertLog(['1, 1']);
123
expect(root).toMatchRenderedOutput('1, 1');
124
});
@@ -162,6 +166,7 @@ describe('ReactFlushSync', () => {
166
]);
167
expect(root).toMatchRenderedOutput('Child');
168
});
169
+ // Effect flushes after paint.
170
assertLog(['Effect']);
171
});
172
@@ -217,6 +222,7 @@ describe('ReactFlushSync', () => {
222
]);
223
expect(root).toMatchRenderedOutput('Child');
224
});
225
+ // Effect flushes after paint.
226
assertLog(['Effect']);
227
});
228
@@ -236,8 +242,10 @@ describe('ReactFlushSync', () => {
242
243
// Passive effects are pending. Calling flushSync should not affect them.
244
ReactNoop.flushSync();
245
+ // Effects still haven't fired.
246
assertLog([]);
247
});
248
+ // Now the effects have fired.
249
assertLog(['Effect']);
250
});
251
});
packages/react-reconciler/src/__tests__/ReactFragment-test.js
+2
@@ -944,6 +944,7 @@ describe('ReactFragment', () => {
944
);
945
946
ReactNoop.render(<Foo condition={false} />);
947
+ // The key warning gets deduped because it's in the same component.
948
await waitForAll([]);
949
950
expect(ops).toEqual(['Update Stateful']);
@@ -955,6 +956,7 @@ describe('ReactFragment', () => {
956
);
957
958
ReactNoop.render(<Foo condition={true} />);
959
+ // The key warning gets deduped because it's in the same component.
960
await waitForAll([]);
961
962
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+48
@@ -299,6 +299,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
299
300
// Resolve the data
301
await resolveText('A');
302
+ // Renders successfully
303
await waitForAll(['Foo', 'Bar', 'A', 'B']);
304
expect(ReactNoop).toMatchRenderedOutput(
305
<>
@@ -375,6 +376,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
376
</Suspense>,
377
);
378
});
379
+ // B suspends. Continue rendering the remaining siblings.
380
await waitForAll(['A', 'Suspend! [B]', 'C', 'D', 'Loading...']);
381
// Did not commit yet.
382
expect(ReactNoop).toMatchRenderedOutput(null);
@@ -382,6 +384,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
384
// Wait for data to resolve
385
await resolveText('B');
386
await waitForAll(['A', 'B', 'C', 'D']);
387
+ // Renders successfully
388
expect(ReactNoop).toMatchRenderedOutput(
389
<>
390
<span prop="A" />
@@ -730,6 +733,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
733
// the update.
734
ReactNoop.expire(10000);
735
await advanceTimers(10000);
736
+ // No additional rendering work is required, since we already prepared
737
+ // the placeholder.
738
assertLog([]);
739
// Should have committed the placeholder.
740
expect(ReactNoop).toMatchRenderedOutput(
@@ -974,6 +979,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
979
// but not by enough to flush the promise or reach the true expiration time.
980
ReactNoop.expire(2000);
981
await advanceTimers(2000);
982
+ // Even flushing won't yield a fallback in a transition.
983
expect(ReactNoop).toMatchRenderedOutput(null);
984
985
await waitForAll([]);
@@ -1014,6 +1020,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1020
1021
await resolveText('Async');
1022
1023
+ // Because we're already showing a fallback, interrupt the current render
1024
+ // and restart immediately.
1025
await waitForAll(['Async', 'Sibling']);
1026
expect(root).toMatchRenderedOutput(
1027
<>
@@ -1081,6 +1089,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1089
1090
// Resolve the promise
1091
await resolveText('Async');
1092
+ // We can now resume rendering
1093
await waitForAll(['Async']);
1094
expect(ReactNoop).toMatchRenderedOutput(<span prop="Async" />);
1095
});
@@ -1106,6 +1115,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1115
1116
// Schedule an update, and suspend for up to 5 seconds.
1117
React.startTransition(() => ReactNoop.render(<App text="A" />));
1118
+ // The update should suspend.
1119
await waitForAll(['Suspend! [A]', 'Loading...']);
1120
expect(ReactNoop).toMatchRenderedOutput(<span prop="S" />);
1121
@@ -1117,6 +1127,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1127
1128
// Schedule another low priority update.
1129
React.startTransition(() => ReactNoop.render(<App text="B" />));
1130
+ // This update should also suspend.
1131
await waitForAll(['Suspend! [B]', 'Loading...']);
1132
expect(ReactNoop).toMatchRenderedOutput(<span prop="S" />);
1133
@@ -1129,6 +1140,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1140
// Flush the remaining work.
1141
await resolveText('A');
1142
await resolveText('B');
1143
+ // Nothing else to render.
1144
await waitForAll([]);
1145
expect(ReactNoop).toMatchRenderedOutput(<span prop="C" />);
1146
});
@@ -1778,6 +1790,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1790
'Commit root',
1791
]);
1792
1793
+ // Flush passive effects.
1794
await waitForAll([
1795
'Effect [A]',
1796
// B's effect should not fire because it suspended
@@ -1823,6 +1836,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1836
'Commit root',
1837
]);
1838
1839
+ // Flush passive effects.
1840
await waitForAll([
1841
// B2's effect should not fire because it suspended
1842
// 'Effect [B2]',
@@ -1863,6 +1877,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1877
});
1878
Scheduler.unstable_advanceTime(100);
1879
await advanceTimers(100);
1880
+ // Start rendering
1881
await waitFor(['Foo']);
1882
// For some reason it took a long time to render Foo.
1883
Scheduler.unstable_advanceTime(1250);
@@ -1878,12 +1893,15 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1893
// Flush some of the time
1894
Scheduler.unstable_advanceTime(450);
1895
await advanceTimers(450);
1896
+ // Because we've already been waiting for so long we can
1897
+ // wait a bit longer. Still nothing...
1898
await waitForAll([]);
1899
expect(ReactNoop).toMatchRenderedOutput(null);
1900
1901
// Eventually we'll show the fallback.
1902
Scheduler.unstable_advanceTime(500);
1903
await advanceTimers(500);
1904
+ // No need to rerender.
1905
await waitForAll([]);
1906
// Since this is a transition, we never fallback.
1907
expect(ReactNoop).toMatchRenderedOutput(null);
@@ -1891,6 +1909,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1909
// Flush the promise completely
1910
await resolveText('A');
1911
await waitForAll(['Foo', 'A']);
1912
+ // Renders successfully
1913
+ // TODO: Why does this render Foo
1914
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
1915
});
1916
@@ -1909,6 +1929,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1929
}
1930
1931
ReactNoop.render(<Foo />);
1932
+ // Start rendering
1933
await waitForAll([
1934
'Foo',
1935
// A suspends
@@ -1925,6 +1946,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1946
Scheduler.unstable_advanceTime(5000);
1947
await advanceTimers(5000);
1948
1949
+ // Retry with the new content.
1950
await waitForAll([
1951
'A',
1952
// B still suspends
@@ -1943,6 +1965,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1965
1966
// Flush the last promise completely
1967
await resolveText('B');
1968
+ // Renders successfully
1969
await waitForAll(['B']);
1970
expect(ReactNoop).toMatchRenderedOutput(
1971
<>
@@ -1967,6 +1990,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1990
}
1991
1992
ReactNoop.render(<Foo />);
1993
+ // Start rendering
1994
await waitForAll([
1995
'Foo',
1996
// A suspends
@@ -1980,6 +2004,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2004
2005
await resolveText('A');
2006
2007
+ // Retry with the new content.
2008
await waitForAll([
2009
'A',
2010
// B still suspends
@@ -1995,6 +2020,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2020
// Before we commit another Promise resolves.
2021
// We're still showing the first loading state.
2022
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
2023
+ // Restart and render the complete content.
2024
await waitForAll(['A', 'B']);
2025
expect(ReactNoop).toMatchRenderedOutput(
2026
<>
@@ -2040,6 +2066,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2066
Scheduler.unstable_advanceTime(500);
2067
jest.advanceTimersByTime(500);
2068
2069
+ // We should have already shown the fallback.
2070
+ // When we wrote this test, we inferred the start time of high priority
2071
+ // updates as way earlier in the past. This test ensures that we don't
2072
+ // use this assumption to add a very long JND.
2073
await waitForAll([]);
2074
// Transitions never fallback.
2075
expect(ReactNoop).toMatchRenderedOutput(null);
@@ -2481,6 +2511,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2511
2512
// Schedule an update at idle pri.
2513
ReactNoop.idleUpdates(() => ReactNoop.render(<Foo renderContent={2} />));
2514
+ // We won't even work on Idle priority.
2515
await waitForAll([]);
2516
2517
// We're still suspended.
@@ -3040,6 +3071,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3071
await act(async () => {
3072
foo.setState({suspend: true});
3073
3074
+ // In the regression that this covers, we would neglect to reset the
3075
+ // current debug phase after suspending (in the catch block), so React
3076
+ // thinks we're still inside the render phase.
3077
await waitFor(['Suspend!']);
3078
3079
// Then when this setState happens, React would incorrectly fire a warning
@@ -3130,6 +3164,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3164
await waitFor(['Commit']);
3165
expect(ReactNoop).toMatchRenderedOutput(<div hidden={true} />);
3166
3167
+ // Partially render through the hidden content.
3168
await waitFor(['Suspend! [A]']);
3169
3170
// Start transition.
@@ -3270,6 +3305,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3305
</>,
3306
);
3307
3308
+ // Now flush the remaining work. The Idle update successfully finishes.
3309
await waitForAll(['C']);
3310
expect(root).toMatchRenderedOutput(<span prop="C" />);
3311
});
@@ -3433,6 +3469,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3469
await act(async () => {
3470
setText('D');
3471
});
3472
+ // Even though the fragment fiber is not part of the return path, we should
3473
+ // be able to finish rendering.
3474
assertLog(['D']);
3475
expect(root).toMatchRenderedOutput(<span prop="D" />);
3476
},
@@ -3513,6 +3551,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3551
setText('E');
3552
});
3553
});
3554
+ // Even though the fragment fiber is not part of the return path, we should
3555
+ // be able to finish rendering.
3556
assertLog(['Suspend! [D]', 'E']);
3557
expect(root).toMatchRenderedOutput(<span prop="E" />);
3558
},
@@ -3622,6 +3662,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3662
});
3663
});
3664
3665
+ // Only the outer part can update. The inner part should still show a
3666
+ // fallback because we haven't finished loading B yet. Otherwise, the
3667
+ // inner text would be inconsistent with the outer text.
3668
assertLog([
3669
'Outer text: B',
3670
'Outer step: 1',
@@ -3882,11 +3925,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3925
ReactNoop.idleUpdates(() => {
3926
setText('B');
3927
});
3928
+ // Suspend the first update. The second update doesn't run because it has
3929
+ // Idle priority.
3930
await waitForAll(['Suspend! [B]', 'Loading...']);
3931
3932
// Commit the fallback. Now we'll try working on Idle.
3933
jest.runAllTimers();
3934
3935
+ // It also suspends.
3936
await waitForAll(['Suspend! [B]']);
3937
});
3938
@@ -3934,6 +3980,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3980
// Before the retry happens, schedule a new update.
3981
setText('B');
3982
3983
+ // The update should be allowed to finish before the retry is attempted.
3984
await waitForPaint(['B']);
3985
expect(root).toMatchRenderedOutput(
3986
<>
@@ -3942,6 +3989,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3989
</>,
3990
);
3991
});
3992
+ // Then do the retry.
3993
assertLog(['Async']);
3994
expect(root).toMatchRenderedOutput(
3995
<>