Codemod tests to waitFor pattern (7/?) (#26307)
This converts some of our test suite to use the `waitFor` test pattern, instead of the `expect(Scheduler).toFlushAndYield` pattern. Most of these changes are automated with jscodeshift, with some slight manual cleanup in certain cases. See #26285 for full context.
Andrew Clark committed
Mar 4, 2023 at 18:03 UTC
3cb5afb82efd56d8af09a942a17ddde5e63d2e80
14 files changed
+635
-737
packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemanticsDOM-test.js
+29
-23
@@ -15,6 +15,8 @@ let ReactDOMClient;
15
let Scheduler;
16
let act;
17
let container;
18
+let waitForAll;
19
+let assertLog;
20
21
describe('ReactSuspenseEffectsSemanticsDOM', () => {
22
beforeEach(() => {
@@ -26,6 +28,10 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
28
Scheduler = require('scheduler');
29
act = require('jest-react').act;
30
31
+ const InternalTestUtils = require('internal-test-utils');
32
+ waitForAll = InternalTestUtils.waitForAll;
33
+ assertLog = InternalTestUtils.assertLog;
34
+
35
container = document.createElement('div');
36
document.body.appendChild(container);
37
});
@@ -139,23 +145,23 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
145
act(() => {
146
root.render(<Parent swap={false} />);
147
});
142
- expect(Scheduler).toHaveYielded(['Loading...']);
148
+ assertLog(['Loading...']);
149
150
await LazyChildA;
145
- expect(Scheduler).toFlushAndYield(['A', 'Ref mount: A']);
151
+ await waitForAll(['A', 'Ref mount: A']);
152
expect(container.innerHTML).toBe('<span>A</span>');
153
154
// Swap the position of A and B
155
ReactDOM.flushSync(() => {
156
root.render(<Parent swap={true} />);
157
});
152
- expect(Scheduler).toHaveYielded(['Loading...', 'Ref unmount: A']);
158
+ assertLog(['Loading...', 'Ref unmount: A']);
159
expect(container.innerHTML).toBe(
160
'<span style="display: none;">A</span>Loading...',
161
);
162
163
await LazyChildB;
158
- expect(Scheduler).toFlushAndYield(['B', 'Ref mount: B']);
164
+ await waitForAll(['B', 'Ref mount: B']);
165
expect(container.innerHTML).toBe('<span>B</span>');
166
});
167
@@ -199,21 +205,21 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
205
act(() => {
206
root.render(<Parent swap={false} />);
207
});
202
- expect(Scheduler).toHaveYielded(['Loading...']);
208
+ assertLog(['Loading...']);
209
210
await LazyChildA;
205
- expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
211
+ await waitForAll(['A', 'Did mount: A']);
212
expect(container.innerHTML).toBe('A');
213
214
// Swap the position of A and B
215
ReactDOM.flushSync(() => {
216
root.render(<Parent swap={true} />);
217
});
212
- expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
218
+ assertLog(['Loading...', 'Will unmount: A']);
219
expect(container.innerHTML).toBe('Loading...');
220
221
await LazyChildB;
216
- expect(Scheduler).toFlushAndYield(['B', 'Did mount: B']);
222
+ await waitForAll(['B', 'Did mount: B']);
223
expect(container.innerHTML).toBe('B');
224
});
225
@@ -251,24 +257,24 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
257
act(() => {
258
root.render(<Parent swap={false} />);
259
});
254
- expect(Scheduler).toHaveYielded(['Loading...']);
260
+ assertLog(['Loading...']);
261
262
await LazyChildA;
257
- expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
263
+ await waitForAll(['A', 'Did mount: A']);
264
expect(container.innerHTML).toBe('A');
265
266
// Swap the position of A and B
267
ReactDOM.flushSync(() => {
268
root.render(<Parent swap={true} />);
269
});
264
- expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
270
+ assertLog(['Loading...', 'Will unmount: A']);
271
expect(container.innerHTML).toBe('Loading...');
272
273
// Destroy the whole tree, including the hidden A
274
ReactDOM.flushSync(() => {
275
root.render(<h1>Hello</h1>);
276
});
271
- expect(Scheduler).toFlushAndYield([]);
277
+ await waitForAll([]);
278
expect(container.innerHTML).toBe('<h1>Hello</h1>');
279
});
280
@@ -318,17 +324,17 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
324
act(() => {
325
root.render(<Parent swap={false} />);
326
});
321
- expect(Scheduler).toHaveYielded(['Loading...']);
327
+ assertLog(['Loading...']);
328
329
await LazyChildA;
324
- expect(Scheduler).toFlushAndYield(['A', 'Ref mount: A']);
330
+ await waitForAll(['A', 'Ref mount: A']);
331
expect(container.innerHTML).toBe('<span>A</span>');
332
333
// Swap the position of A and B
334
ReactDOM.flushSync(() => {
335
root.render(<Parent swap={true} />);
336
});
331
- expect(Scheduler).toHaveYielded(['Loading...', 'Ref unmount: A']);
337
+ assertLog(['Loading...', 'Ref unmount: A']);
338
expect(container.innerHTML).toBe(
339
'<span style="display: none;">A</span>Loading...',
340
);
@@ -337,7 +343,7 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
343
ReactDOM.flushSync(() => {
344
root.render(<h1>Hello</h1>);
345
});
340
- expect(Scheduler).toFlushAndYield([]);
346
+ await waitForAll([]);
347
expect(container.innerHTML).toBe('<h1>Hello</h1>');
348
});
349
@@ -381,24 +387,24 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
387
act(() => {
388
root.render(<Parent swap={false} />);
389
});
384
- expect(Scheduler).toHaveYielded(['Loading...']);
390
+ assertLog(['Loading...']);
391
392
await LazyChildA;
387
- expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
393
+ await waitForAll(['A', 'Did mount: A']);
394
expect(container.innerHTML).toBe('A');
395
396
// Swap the position of A and B
397
ReactDOM.flushSync(() => {
398
root.render(<Parent swap={true} />);
399
});
394
- expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
400
+ assertLog(['Loading...', 'Will unmount: A']);
401
expect(container.innerHTML).toBe('Loading...');
402
403
// Destroy the whole tree, including the hidden A
404
ReactDOM.flushSync(() => {
405
root.render(<h1>Hello</h1>);
406
});
401
- expect(Scheduler).toFlushAndYield([]);
407
+ await waitForAll([]);
408
expect(container.innerHTML).toBe('<h1>Hello</h1>');
409
});
410
@@ -432,12 +438,12 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
438
439
// Initial render
440
ReactDOM.render(<App showMore={false} />, container);
435
- expect(Scheduler).toHaveYielded(['Child', 'Mount']);
441
+ assertLog(['Child', 'Mount']);
442
443
// Update that suspends, causing the existing tree to switches it to
444
// a fallback.
445
ReactDOM.render(<App showMore={true} />, container);
440
- expect(Scheduler).toHaveYielded([
446
+ assertLog([
447
'Child',
448
'Loading...',
449
@@ -448,6 +454,6 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
454
455
// Delete the tree and unmount the effect
456
ReactDOM.render(null, container);
451
- expect(Scheduler).toHaveYielded(['Unmount']);
457
+ assertLog(['Unmount']);
458
});
459
});
packages/react-reconciler/src/__tests__/ReactSuspenseFallback-test.js
+16
-12
@@ -13,6 +13,7 @@ let Suspense;
13
let getCacheForType;
14
let caches;
15
let seededCache;
16
+let waitForAll;
17
18
describe('ReactSuspenseFallback', () => {
19
beforeEach(() => {
@@ -25,6 +26,9 @@ describe('ReactSuspenseFallback', () => {
26
getCacheForType = React.unstable_getCacheForType;
27
caches = [];
28
seededCache = null;
29
+
30
+ const InternalTestUtils = require('internal-test-utils');
31
+ waitForAll = InternalTestUtils.waitForAll;
32
});
33
34
function createTextCache() {
@@ -128,26 +132,26 @@ describe('ReactSuspenseFallback', () => {
132
}
133
134
// @gate enableLegacyCache
131
- it('suspends and shows fallback', () => {
135
+ it('suspends and shows fallback', async () => {
136
ReactNoop.render(
137
<Suspense fallback={<Text text="Loading..." />}>
138
<AsyncText text="A" ms={100} />
139
</Suspense>,
140
);
141
138
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
142
+ await waitForAll(['Suspend! [A]', 'Loading...']);
143
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
144
});
145
146
// @gate enableLegacyCache
143
- it('suspends and shows null fallback', () => {
147
+ it('suspends and shows null fallback', async () => {
148
ReactNoop.render(
149
<Suspense fallback={null}>
150
<AsyncText text="A" ms={100} />
151
</Suspense>,
152
);
153
150
- expect(Scheduler).toFlushAndYield([
154
+ await waitForAll([
155
'Suspend! [A]',
156
// null
157
]);
@@ -155,14 +159,14 @@ describe('ReactSuspenseFallback', () => {
159
});
160
161
// @gate enableLegacyCache
158
- it('suspends and shows undefined fallback', () => {
162
+ it('suspends and shows undefined fallback', async () => {
163
ReactNoop.render(
164
<Suspense>
165
<AsyncText text="A" ms={100} />
166
</Suspense>,
167
);
168
165
- expect(Scheduler).toFlushAndYield([
169
+ await waitForAll([
170
'Suspend! [A]',
171
// null
172
]);
@@ -170,7 +174,7 @@ describe('ReactSuspenseFallback', () => {
174
});
175
176
// @gate enableLegacyCache
173
- it('suspends and shows inner fallback', () => {
177
+ it('suspends and shows inner fallback', async () => {
178
ReactNoop.render(
179
<Suspense fallback={<Text text="Should not show..." />}>
180
<Suspense fallback={<Text text="Loading..." />}>
@@ -179,12 +183,12 @@ describe('ReactSuspenseFallback', () => {
183
</Suspense>,
184
);
185
182
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
186
+ await waitForAll(['Suspend! [A]', 'Loading...']);
187
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
188
});
189
190
// @gate enableLegacyCache
187
- it('suspends and shows inner undefined fallback', () => {
191
+ it('suspends and shows inner undefined fallback', async () => {
192
ReactNoop.render(
193
<Suspense fallback={<Text text="Should not show..." />}>
194
<Suspense>
@@ -193,7 +197,7 @@ describe('ReactSuspenseFallback', () => {
197
</Suspense>,
198
);
199
196
- expect(Scheduler).toFlushAndYield([
200
+ await waitForAll([
201
'Suspend! [A]',
202
// null
203
]);
@@ -201,7 +205,7 @@ describe('ReactSuspenseFallback', () => {
205
});
206
207
// @gate enableLegacyCache
204
- it('suspends and shows inner null fallback', () => {
208
+ it('suspends and shows inner null fallback', async () => {
209
ReactNoop.render(
210
<Suspense fallback={<Text text="Should not show..." />}>
211
<Suspense fallback={null}>
@@ -210,7 +214,7 @@ describe('ReactSuspenseFallback', () => {
214
</Suspense>,
215
);
216
213
- expect(Scheduler).toFlushAndYield([
217
+ await waitForAll([
218
'Suspend! [A]',
219
// null
220
]);
packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
+128
-183
@@ -5,6 +5,9 @@ let act;
5
let Profiler;
6
let Suspense;
7
let SuspenseList;
8
+let waitForAll;
9
+let assertLog;
10
+let waitFor;
11
12
describe('ReactSuspenseList', () => {
13
beforeEach(() => {
@@ -19,6 +22,11 @@ describe('ReactSuspenseList', () => {
22
if (gate(flags => flags.enableSuspenseList)) {
23
SuspenseList = React.SuspenseList;
24
}
25
+
26
+ const InternalTestUtils = require('internal-test-utils');
27
+ waitForAll = InternalTestUtils.waitForAll;
28
+ assertLog = InternalTestUtils.assertLog;
29
+ waitFor = InternalTestUtils.waitFor;
30
});
31
32
function Text(props) {
@@ -106,22 +114,22 @@ describe('ReactSuspenseList', () => {
114
});
115
116
// @gate enableSuspenseList
109
- it('warns if a single element is passed to a "forwards" list', () => {
117
+ it('warns if a single element is passed to a "forwards" list', async () => {
118
function Foo({children}) {
119
return <SuspenseList revealOrder="forwards">{children}</SuspenseList>;
120
}
121
122
ReactNoop.render(<Foo />);
123
// No warning
116
- Scheduler.unstable_flushAll();
124
+ await waitForAll([]);
125
126
ReactNoop.render(<Foo>{null}</Foo>);
127
// No warning
120
- Scheduler.unstable_flushAll();
128
+ await waitForAll([]);
129
130
ReactNoop.render(<Foo>{false}</Foo>);
131
// No warning
124
- Scheduler.unstable_flushAll();
132
+ await waitForAll([]);
133
134
ReactNoop.render(
135
<Foo>
@@ -213,7 +221,7 @@ describe('ReactSuspenseList', () => {
221
222
ReactNoop.render(<Foo />);
223
216
- expect(Scheduler).toFlushAndYield([
224
+ await waitForAll([
225
'A',
226
'Suspend! [B]',
227
'Loading B',
@@ -231,7 +239,7 @@ describe('ReactSuspenseList', () => {
239
240
await C.resolve();
241
234
- expect(Scheduler).toFlushAndYield(['C']);
242
+ await waitForAll(['C']);
243
244
expect(ReactNoop).toMatchRenderedOutput(
245
<>
@@ -243,7 +251,7 @@ describe('ReactSuspenseList', () => {
251
252
await B.resolve();
253
246
- expect(Scheduler).toFlushAndYield(['B']);
254
+ await waitForAll(['B']);
255
256
expect(ReactNoop).toMatchRenderedOutput(
257
<>
@@ -280,13 +288,7 @@ describe('ReactSuspenseList', () => {
288
289
ReactNoop.renderLegacySyncRoot(<Foo />);
290
283
- expect(Scheduler).toHaveYielded([
284
- 'A',
285
- 'Suspend! [B]',
286
- 'Loading B',
287
- 'Suspend! [C]',
288
- 'Loading C',
289
- ]);
291
+ assertLog(['A', 'Suspend! [B]', 'Loading B', 'Suspend! [C]', 'Loading C']);
292
293
expect(ReactNoop).toMatchRenderedOutput(
294
<>
@@ -300,7 +302,7 @@ describe('ReactSuspenseList', () => {
302
C.resolve();
303
});
304
303
- expect(Scheduler).toHaveYielded(['C']);
305
+ assertLog(['C']);
306
307
expect(ReactNoop).toMatchRenderedOutput(
308
<>
@@ -314,7 +316,7 @@ describe('ReactSuspenseList', () => {
316
B.resolve();
317
});
318
317
- expect(Scheduler).toHaveYielded(['B']);
319
+ assertLog(['B']);
320
321
expect(ReactNoop).toMatchRenderedOutput(
322
<>
@@ -351,7 +353,7 @@ describe('ReactSuspenseList', () => {
353
354
ReactNoop.render(<Foo />);
355
354
- expect(Scheduler).toFlushAndYield([
356
+ await waitForAll([
357
'A',
358
'Suspend! [B]',
359
'Loading B',
@@ -372,7 +374,7 @@ describe('ReactSuspenseList', () => {
374
375
await B.resolve();
376
375
- expect(Scheduler).toFlushAndYield(['A', 'B', 'Suspend! [C]']);
377
+ await waitForAll(['A', 'B', 'Suspend! [C]']);
378
379
expect(ReactNoop).toMatchRenderedOutput(
380
<>
@@ -384,7 +386,7 @@ describe('ReactSuspenseList', () => {
386
387
await C.resolve();
388
387
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
389
+ await waitForAll(['A', 'B', 'C']);
390
391
expect(ReactNoop).toMatchRenderedOutput(
392
<>
@@ -425,7 +427,7 @@ describe('ReactSuspenseList', () => {
427
428
ReactNoop.render(<Foo />);
429
428
- expect(Scheduler).toFlushAndYield([
430
+ await waitForAll([
431
'A',
432
'Suspend! [B]',
433
'Loading B',
@@ -450,7 +452,7 @@ describe('ReactSuspenseList', () => {
452
453
await B.resolve();
454
453
- expect(Scheduler).toFlushAndYield(['A', 'B', 'Suspend! [C]']);
455
+ await waitForAll(['A', 'B', 'Suspend! [C]']);
456
457
expect(ReactNoop).toMatchRenderedOutput(
458
<>
@@ -466,7 +468,7 @@ describe('ReactSuspenseList', () => {
468
469
await C.resolve();
470
469
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
471
+ await waitForAll(['A', 'B', 'C']);
472
473
expect(ReactNoop).toMatchRenderedOutput(
474
<>
@@ -510,7 +512,7 @@ describe('ReactSuspenseList', () => {
512
513
ReactNoop.render(<Foo />);
514
513
- expect(Scheduler).toFlushAndYield([
515
+ await waitForAll([
516
'A',
517
'B',
518
'Suspend! [C]',
@@ -532,7 +534,7 @@ describe('ReactSuspenseList', () => {
534
535
await C.resolve();
536
535
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
537
+ await waitForAll(['A', 'B', 'C']);
538
539
expect(ReactNoop).toMatchRenderedOutput(
540
<>
@@ -572,7 +574,7 @@ describe('ReactSuspenseList', () => {
574
575
ReactNoop.render(<Foo />);
576
575
- expect(Scheduler).toFlushAndYield([
577
+ await waitForAll([
578
'A',
579
'B',
580
'Suspend! [C]',
@@ -592,7 +594,7 @@ describe('ReactSuspenseList', () => {
594
595
await C.resolve();
596
595
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
597
+ await waitForAll(['A', 'B', 'C']);
598
599
expect(ReactNoop).toMatchRenderedOutput(
600
<>
@@ -640,7 +642,7 @@ describe('ReactSuspenseList', () => {
642
// Mount
643
await A.resolve();
644
ReactNoop.render(<Foo step={0} />);
643
- expect(Scheduler).toFlushAndYield([
645
+ await waitForAll([
646
'A',
647
'Suspend! [B]',
648
'Loading B',
@@ -654,7 +656,7 @@ describe('ReactSuspenseList', () => {
656
</>,
657
);
658
await B.resolve();
657
- expect(Scheduler).toFlushAndYield(['A', 'B']);
659
+ await waitForAll(['A', 'B']);
660
expect(ReactNoop).toMatchRenderedOutput(
661
<>
662
<span>A</span>
@@ -665,7 +667,7 @@ describe('ReactSuspenseList', () => {
667
// Update
668
await C.resolve();
669
ReactNoop.render(<Foo step={1} />);
668
- expect(Scheduler).toFlushAndYield([
670
+ await waitForAll([
671
'C',
672
'Suspend! [D]',
673
'Loading D',
@@ -679,7 +681,7 @@ describe('ReactSuspenseList', () => {
681
</>,
682
);
683
await D.resolve();
682
- expect(Scheduler).toFlushAndYield(['C', 'D']);
684
+ await waitForAll(['C', 'D']);
685
expect(ReactNoop).toMatchRenderedOutput(
686
<>
687
<span>C</span>
@@ -724,20 +726,20 @@ describe('ReactSuspenseList', () => {
726
727
ReactNoop.render(<Foo />);
728
727
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading']);
729
+ await waitForAll(['Suspend! [A]', 'Loading']);
730
731
expect(ReactNoop).toMatchRenderedOutput(<span>Loading</span>);
732
733
await A.resolve();
734
733
- expect(Scheduler).toFlushAndYield(['A']);
735
+ await waitForAll(['A']);
736
737
expect(ReactNoop).toMatchRenderedOutput(<span>A</span>);
738
739
// Let's do an update that should consult the avoided boundaries.
740
ReactNoop.render(<Foo showMore={true} />);
741
740
- expect(Scheduler).toFlushAndYield([
742
+ await waitForAll([
743
'A',
744
'Suspend! [B]',
745
'Loading B',
@@ -763,7 +765,7 @@ describe('ReactSuspenseList', () => {
765
766
await B.resolve();
767
766
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]']);
768
+ await waitForAll(['B', 'Suspend! [C]']);
769
770
// Even though we could now show B, we're still waiting on C.
771
expect(ReactNoop).toMatchRenderedOutput(
@@ -776,7 +778,7 @@ describe('ReactSuspenseList', () => {
778
779
await C.resolve();
780
779
- expect(Scheduler).toFlushAndYield(['B', 'C']);
781
+ await waitForAll(['B', 'C']);
782
783
expect(ReactNoop).toMatchRenderedOutput(
784
<>
@@ -817,7 +819,7 @@ describe('ReactSuspenseList', () => {
819
820
ReactNoop.render(<Foo />);
821
820
- expect(Scheduler).toFlushAndYield([
822
+ await waitForAll([
823
'Suspend! [A]',
824
// null
825
]);
@@ -826,14 +828,14 @@ describe('ReactSuspenseList', () => {
828
829
await A.resolve();
830
829
- expect(Scheduler).toFlushAndYield(['A']);
831
+ await waitForAll(['A']);
832
833
expect(ReactNoop).toMatchRenderedOutput(<span>A</span>);
834
835
// Let's do an update that should consult the avoided boundaries.
836
ReactNoop.render(<Foo showMore={true} />);
837
836
- expect(Scheduler).toFlushAndYield([
838
+ await waitForAll([
839
'A',
840
'Suspend! [B]',
841
// null
@@ -853,14 +855,14 @@ describe('ReactSuspenseList', () => {
855
856
await B.resolve();
857
856
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]']);
858
+ await waitForAll(['B', 'Suspend! [C]']);
859
860
// Even though we could now show B, we're still waiting on C.
861
expect(ReactNoop).toMatchRenderedOutput(<span>A</span>);
862
863
await C.resolve();
864
863
- expect(Scheduler).toFlushAndYield(['B', 'C']);
865
+ await waitForAll(['B', 'C']);
866
867
expect(ReactNoop).toMatchRenderedOutput(
868
<>
@@ -897,12 +899,7 @@ describe('ReactSuspenseList', () => {
899
900
ReactNoop.render(<Foo />);
901
900
- expect(Scheduler).toFlushAndYield([
901
- 'Suspend! [A]',
902
- 'Loading A',
903
- 'Loading B',
904
- 'Loading C',
905
- ]);
902
+ await waitForAll(['Suspend! [A]', 'Loading A', 'Loading B', 'Loading C']);
903
904
expect(ReactNoop).toMatchRenderedOutput(
905
<>
@@ -914,7 +911,7 @@ describe('ReactSuspenseList', () => {
911
912
await A.resolve();
913
917
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]']);
914
+ await waitForAll(['A', 'Suspend! [B]']);
915
916
expect(ReactNoop).toMatchRenderedOutput(
917
<>
@@ -926,7 +923,7 @@ describe('ReactSuspenseList', () => {
923
924
await B.resolve();
925
929
- expect(Scheduler).toFlushAndYield(['B', 'C']);
926
+ await waitForAll(['B', 'C']);
927
928
expect(ReactNoop).toMatchRenderedOutput(
929
<>
@@ -963,12 +960,7 @@ describe('ReactSuspenseList', () => {
960
961
ReactNoop.render(<Foo />);
962
966
- expect(Scheduler).toFlushAndYield([
967
- 'Suspend! [C]',
968
- 'Loading C',
969
- 'Loading B',
970
- 'Loading A',
971
- ]);
963
+ await waitForAll(['Suspend! [C]', 'Loading C', 'Loading B', 'Loading A']);
964
965
expect(ReactNoop).toMatchRenderedOutput(
966
<>
@@ -980,7 +972,7 @@ describe('ReactSuspenseList', () => {
972
973
await C.resolve();
974
983
- expect(Scheduler).toFlushAndYield(['C', 'Suspend! [B]']);
975
+ await waitForAll(['C', 'Suspend! [B]']);
976
977
expect(ReactNoop).toMatchRenderedOutput(
978
<>
@@ -992,7 +984,7 @@ describe('ReactSuspenseList', () => {
984
985
await B.resolve();
986
995
- expect(Scheduler).toFlushAndYield(['B', 'A']);
987
+ await waitForAll(['B', 'A']);
988
989
expect(ReactNoop).toMatchRenderedOutput(
990
<>
@@ -1036,7 +1028,7 @@ describe('ReactSuspenseList', () => {
1028
/>,
1029
);
1030
1039
- expect(Scheduler).toFlushAndYield(['B', 'D']);
1031
+ await waitForAll(['B', 'D']);
1032
1033
expect(ReactNoop).toMatchRenderedOutput(
1034
<>
@@ -1059,7 +1051,7 @@ describe('ReactSuspenseList', () => {
1051
/>,
1052
);
1053
1062
- expect(Scheduler).toFlushAndYield([
1054
+ await waitForAll([
1055
'Suspend! [A]',
1056
'Loading A',
1057
'B',
@@ -1087,7 +1079,7 @@ describe('ReactSuspenseList', () => {
1079
1080
await A.resolve();
1081
1090
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [C]']);
1082
+ await waitForAll(['A', 'Suspend! [C]']);
1083
1084
// Even though we could show A, it is still in a fallback state because
1085
// C is not yet resolved. We need to resolve everything in the head first.
@@ -1104,7 +1096,7 @@ describe('ReactSuspenseList', () => {
1096
1097
await C.resolve();
1098
1107
- expect(Scheduler).toFlushAndYield(['A', 'C', 'Suspend! [E]']);
1099
+ await waitForAll(['A', 'C', 'Suspend! [E]']);
1100
1101
// We can now resolve the full head.
1102
expect(ReactNoop).toMatchRenderedOutput(
@@ -1120,7 +1112,7 @@ describe('ReactSuspenseList', () => {
1112
1113
await E.resolve();
1114
1123
- expect(Scheduler).toFlushAndYield(['E', 'Suspend! [F]']);
1115
+ await waitForAll(['E', 'Suspend! [F]']);
1116
1117
// In the tail we can resolve one-by-one.
1118
expect(ReactNoop).toMatchRenderedOutput(
@@ -1147,7 +1139,7 @@ describe('ReactSuspenseList', () => {
1139
/>,
1140
);
1141
1150
- expect(Scheduler).toFlushAndYield(['D', 'E', 'F']);
1142
+ await waitForAll(['D', 'E', 'F']);
1143
1144
expect(ReactNoop).toMatchRenderedOutput(
1145
<>
@@ -1203,7 +1195,7 @@ describe('ReactSuspenseList', () => {
1195
]}
1196
/>,
1197
);
1206
- expect(Scheduler).toFlushAndYield(['F', 'E', 'D', 'C', 'B', 'A']);
1198
+ await waitForAll(['F', 'E', 'D', 'C', 'B', 'A']);
1199
expect(ReactNoop).toMatchRenderedOutput(
1200
<>
1201
<span>A</span>
@@ -1229,7 +1221,7 @@ describe('ReactSuspenseList', () => {
1221
/>,
1222
);
1223
1232
- expect(Scheduler).toFlushAndYield([
1224
+ await waitForAll([
1225
'Suspend! [A]',
1226
'Loading A',
1227
'Suspend! [B]',
@@ -1273,7 +1265,7 @@ describe('ReactSuspenseList', () => {
1265
1266
await F.resolve();
1267
1276
- expect(Scheduler).toFlushAndYield(['Suspend! [D]', 'F']);
1268
+ await waitForAll(['Suspend! [D]', 'F']);
1269
1270
// Even though we could show F, it is still in a fallback state because
1271
// E is not yet resolved. We need to resolve everything in the head first.
@@ -1294,7 +1286,7 @@ describe('ReactSuspenseList', () => {
1286
1287
await D.resolve();
1288
1297
- expect(Scheduler).toFlushAndYield(['D', 'F', 'Suspend! [B]']);
1289
+ await waitForAll(['D', 'F', 'Suspend! [B]']);
1290
1291
// We can now resolve the full head.
1292
expect(ReactNoop).toMatchRenderedOutput(
@@ -1312,7 +1304,7 @@ describe('ReactSuspenseList', () => {
1304
1305
await B.resolve();
1306
1315
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [A]']);
1307
+ await waitForAll(['B', 'Suspend! [A]']);
1308
1309
// In the tail we can resolve one-by-one.
1310
expect(ReactNoop).toMatchRenderedOutput(
@@ -1329,7 +1321,7 @@ describe('ReactSuspenseList', () => {
1321
1322
await A.resolve();
1323
1332
- expect(Scheduler).toFlushAndYield(['A']);
1324
+ await waitForAll(['A']);
1325
1326
expect(ReactNoop).toMatchRenderedOutput(
1327
<>
@@ -1366,12 +1358,12 @@ describe('ReactSuspenseList', () => {
1358
ReactNoop.render(<Foo />);
1359
});
1360
1369
- expect(Scheduler).toFlushAndYieldThrough(['A']);
1361
+ await waitFor(['A']);
1362
1363
Scheduler.unstable_advanceTime(200);
1364
jest.advanceTimersByTime(200);
1365
1374
- expect(Scheduler).toFlushAndYieldThrough(['B']);
1366
+ await waitFor(['B']);
1367
1368
Scheduler.unstable_advanceTime(300);
1369
jest.advanceTimersByTime(300);
@@ -1383,7 +1375,7 @@ describe('ReactSuspenseList', () => {
1375
// Time has now elapsed for so long that we're just going to give up
1376
// rendering the rest of the content. So that we can at least show
1377
// something.
1386
- expect(Scheduler).toFlushAndYieldThrough([
1378
+ await waitFor([
1379
'Loading C',
1380
'C', // I'll flush through into the next render so that the first commits.
1381
]);
@@ -1397,7 +1389,7 @@ describe('ReactSuspenseList', () => {
1389
);
1390
1391
// Then we do a second pass to commit the last item.
1400
- expect(Scheduler).toFlushAndYield([]);
1392
+ await waitForAll([]);
1393
1394
expect(ReactNoop).toMatchRenderedOutput(
1395
<>
@@ -1432,13 +1424,13 @@ describe('ReactSuspenseList', () => {
1424
1425
ReactNoop.render(<Foo />);
1426
1435
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading A']);
1427
+ await waitForAll(['Suspend! [A]', 'Loading A']);
1428
1429
expect(ReactNoop).toMatchRenderedOutput(<span>Loading A</span>);
1430
1431
await A.resolve();
1432
1441
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'Loading B']);
1433
+ await waitForAll(['A', 'Suspend! [B]', 'Loading B']);
1434
1435
// Incremental loading is suspended.
1436
jest.advanceTimersByTime(500);
@@ -1452,7 +1444,7 @@ describe('ReactSuspenseList', () => {
1444
1445
await B.resolve();
1446
1455
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]', 'Loading C']);
1447
+ await waitForAll(['B', 'Suspend! [C]', 'Loading C']);
1448
1449
// Incremental loading is suspended.
1450
jest.advanceTimersByTime(500);
@@ -1467,7 +1459,7 @@ describe('ReactSuspenseList', () => {
1459
1460
await C.resolve();
1461
1470
- expect(Scheduler).toFlushAndYield(['C']);
1462
+ await waitForAll(['C']);
1463
1464
expect(ReactNoop).toMatchRenderedOutput(
1465
<>
@@ -1546,12 +1538,12 @@ describe('ReactSuspenseList', () => {
1538
ReactNoop.render(<Foo />);
1539
});
1540
1549
- expect(Scheduler).toFlushAndYieldThrough(['A']);
1541
+ await waitFor(['A']);
1542
1543
Scheduler.unstable_advanceTime(200);
1544
jest.advanceTimersByTime(200);
1545
1554
- expect(Scheduler).toFlushAndYieldThrough(['B']);
1546
+ await waitFor(['B']);
1547
1548
Scheduler.unstable_advanceTime(300);
1549
jest.advanceTimersByTime(300);
@@ -1563,7 +1555,7 @@ describe('ReactSuspenseList', () => {
1555
// Time has now elapsed for so long that we're just going to give up
1556
// rendering the rest of the content. So that we can at least show
1557
// something.
1566
- expect(Scheduler).toFlushAndYieldThrough([
1558
+ await waitFor([
1559
'Loading C',
1560
'C', // I'll flush through into the next render so that the first commits.
1561
]);
@@ -1577,7 +1569,7 @@ describe('ReactSuspenseList', () => {
1569
);
1570
1571
// Then we do a second pass to commit the last two items.
1580
- expect(Scheduler).toFlushAndYield(['D']);
1572
+ await waitForAll(['D']);
1573
1574
expect(ReactNoop).toMatchRenderedOutput(
1575
<>
@@ -1622,7 +1614,7 @@ describe('ReactSuspenseList', () => {
1614
await A.resolve();
1615
await D.resolve();
1616
1625
- expect(Scheduler).toFlushAndYield(['A', 'D']);
1617
+ await waitForAll(['A', 'D']);
1618
1619
// First render commits A and D.
1620
expect(ReactNoop).toMatchRenderedOutput(
@@ -1646,7 +1638,7 @@ describe('ReactSuspenseList', () => {
1638
/>,
1639
);
1640
1649
- expect(Scheduler).toFlushAndYield([
1641
+ await waitForAll([
1642
'A',
1643
'Suspend! [B]',
1644
'Loading B',
@@ -1673,7 +1665,7 @@ describe('ReactSuspenseList', () => {
1665
1666
await B.resolve();
1667
1676
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]']);
1668
+ await waitForAll(['B', 'Suspend! [C]']);
1669
1670
// Incremental loading is suspended.
1671
jest.advanceTimersByTime(500);
@@ -1693,13 +1685,7 @@ describe('ReactSuspenseList', () => {
1685
await C.resolve();
1686
await E.resolve();
1687
1696
- expect(Scheduler).toFlushAndYield([
1697
- 'B',
1698
- 'C',
1699
- 'E',
1700
- 'Suspend! [F]',
1701
- 'Loading F',
1702
- ]);
1688
+ await waitForAll(['B', 'C', 'E', 'Suspend! [F]', 'Loading F']);
1689
1690
jest.advanceTimersByTime(500);
1691
@@ -1716,7 +1702,7 @@ describe('ReactSuspenseList', () => {
1702
1703
await F.resolve();
1704
1719
- expect(Scheduler).toFlushAndYield(['F']);
1705
+ await waitForAll(['F']);
1706
1707
jest.advanceTimersByTime(500);
1708
@@ -1765,7 +1751,7 @@ describe('ReactSuspenseList', () => {
1751
await C.resolve();
1752
await F.resolve();
1753
1768
- expect(Scheduler).toFlushAndYield(['F', 'C']);
1754
+ await waitForAll(['F', 'C']);
1755
1756
// First render commits C and F.
1757
expect(ReactNoop).toMatchRenderedOutput(
@@ -1789,7 +1775,7 @@ describe('ReactSuspenseList', () => {
1775
/>,
1776
);
1777
1792
- expect(Scheduler).toFlushAndYield([
1778
+ await waitForAll([
1779
'C',
1780
'Suspend! [D]',
1781
'Loading D',
@@ -1816,7 +1802,7 @@ describe('ReactSuspenseList', () => {
1802
1803
await D.resolve();
1804
1819
- expect(Scheduler).toFlushAndYield(['D', 'Suspend! [E]']);
1805
+ await waitForAll(['D', 'Suspend! [E]']);
1806
1807
// Incremental loading is suspended.
1808
jest.advanceTimersByTime(500);
@@ -1841,13 +1827,7 @@ describe('ReactSuspenseList', () => {
1827
await D.resolve();
1828
await E.resolve();
1829
1844
- expect(Scheduler).toFlushAndYield([
1845
- 'D',
1846
- 'E',
1847
- 'B',
1848
- 'Suspend! [A]',
1849
- 'Loading A',
1850
- ]);
1830
+ await waitForAll(['D', 'E', 'B', 'Suspend! [A]', 'Loading A']);
1831
1832
jest.advanceTimersByTime(500);
1833
@@ -1864,7 +1844,7 @@ describe('ReactSuspenseList', () => {
1844
1845
await A.resolve();
1846
1867
- expect(Scheduler).toFlushAndYield(['A']);
1847
+ await waitForAll(['A']);
1848
1849
jest.advanceTimersByTime(500);
1850
@@ -1916,7 +1896,7 @@ describe('ReactSuspenseList', () => {
1896
1897
await A.resolve();
1898
1919
- expect(Scheduler).toFlushAndYield(['A', 'D']);
1899
+ await waitForAll(['A', 'D']);
1900
1901
// First render commits A and D.
1902
expect(ReactNoop).toMatchRenderedOutput(
@@ -1941,7 +1921,7 @@ describe('ReactSuspenseList', () => {
1921
/>,
1922
);
1923
1944
- expect(Scheduler).toFlushAndYield([
1924
+ await waitForAll([
1925
'A',
1926
'Suspend! [B]',
1927
'Loading B',
@@ -1976,7 +1956,7 @@ describe('ReactSuspenseList', () => {
1956
1957
await B.resolve();
1958
1979
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]']);
1959
+ await waitForAll(['B', 'Suspend! [C]']);
1960
1961
// Incremental loading is suspended.
1962
jest.advanceTimersByTime(500);
@@ -1999,13 +1979,7 @@ describe('ReactSuspenseList', () => {
1979
await D.resolve();
1980
await E.resolve();
1981
2002
- expect(Scheduler).toFlushAndYield([
2003
- 'C',
2004
- 'D',
2005
- 'E',
2006
- 'Suspend! [F]',
2007
- 'Loading F',
2008
- ]);
1982
+ await waitForAll(['C', 'D', 'E', 'Suspend! [F]', 'Loading F']);
1983
1984
jest.advanceTimersByTime(500);
1985
@@ -2022,7 +1996,7 @@ describe('ReactSuspenseList', () => {
1996
1997
await F.resolve();
1998
2025
- expect(Scheduler).toFlushAndYield(['F']);
1999
+ await waitForAll(['F']);
2000
2001
jest.advanceTimersByTime(500);
2002
@@ -2062,13 +2036,13 @@ describe('ReactSuspenseList', () => {
2036
2037
ReactNoop.render(<Foo />);
2038
2065
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading A']);
2039
+ await waitForAll(['Suspend! [A]', 'Loading A']);
2040
2041
expect(ReactNoop).toMatchRenderedOutput(null);
2042
2043
await A.resolve();
2044
2071
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'Loading B']);
2045
+ await waitForAll(['A', 'Suspend! [B]', 'Loading B']);
2046
2047
// Incremental loading is suspended.
2048
jest.advanceTimersByTime(500);
@@ -2077,7 +2051,7 @@ describe('ReactSuspenseList', () => {
2051
2052
await B.resolve();
2053
2080
- expect(Scheduler).toFlushAndYield(['B', 'Suspend! [C]', 'Loading C']);
2054
+ await waitForAll(['B', 'Suspend! [C]', 'Loading C']);
2055
2056
// Incremental loading is suspended.
2057
jest.advanceTimersByTime(500);
@@ -2091,7 +2065,7 @@ describe('ReactSuspenseList', () => {
2065
2066
await C.resolve();
2067
2094
- expect(Scheduler).toFlushAndYield(['C']);
2068
+ await waitForAll(['C']);
2069
2070
expect(ReactNoop).toMatchRenderedOutput(
2071
<>
@@ -2129,7 +2103,7 @@ describe('ReactSuspenseList', () => {
2103
2104
ReactNoop.render(<Foo />);
2105
2132
- expect(Scheduler).toFlushAndYield([
2106
+ await waitForAll([
2107
'A',
2108
'Suspend! [B]',
2109
'Loading B',
@@ -2153,7 +2127,7 @@ describe('ReactSuspenseList', () => {
2127
2128
await B.resolve();
2129
2156
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C', 'D']);
2130
+ await waitForAll(['A', 'B', 'C', 'D']);
2131
2132
expect(ReactNoop).toMatchRenderedOutput(
2133
<>
@@ -2189,19 +2163,13 @@ describe('ReactSuspenseList', () => {
2163
2164
ReactNoop.render(<Foo />);
2165
2192
- expect(Scheduler).toFlushAndYield([
2193
- 'A',
2194
- 'Suspend! [B]',
2195
- 'Loading B',
2196
- 'C',
2197
- 'Loading C',
2198
- ]);
2166
+ await waitForAll(['A', 'Suspend! [B]', 'Loading B', 'C', 'Loading C']);
2167
2168
expect(ReactNoop).toMatchRenderedOutput(<span>Loading C</span>);
2169
2170
await B.resolve();
2171
2204
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
2172
+ await waitForAll(['A', 'B', 'C']);
2173
2174
expect(ReactNoop).toMatchRenderedOutput(
2175
<>
@@ -2238,7 +2206,7 @@ describe('ReactSuspenseList', () => {
2206
2207
ReactNoop.render(<Foo showB={false} />);
2208
2241
- expect(Scheduler).toFlushAndYield(['A', 'C']);
2209
+ await waitForAll(['A', 'C']);
2210
2211
expect(ReactNoop).toMatchRenderedOutput(
2212
<>
@@ -2251,14 +2219,7 @@ describe('ReactSuspenseList', () => {
2219
// so we're now effectively in "together" mode for the head.
2220
ReactNoop.render(<Foo showB={true} />);
2221
2254
- expect(Scheduler).toFlushAndYield([
2255
- 'A',
2256
- 'Suspend! [B]',
2257
- 'Loading B',
2258
- 'C',
2259
- 'A',
2260
- 'C',
2261
- ]);
2222
+ await waitForAll(['A', 'Suspend! [B]', 'Loading B', 'C', 'A', 'C']);
2223
2224
expect(ReactNoop).toMatchRenderedOutput(
2225
<>
@@ -2269,7 +2230,7 @@ describe('ReactSuspenseList', () => {
2230
2231
await B.resolve();
2232
2272
- expect(Scheduler).toFlushAndYield(['B']);
2233
+ await waitForAll(['B']);
2234
2235
expect(ReactNoop).toMatchRenderedOutput(
2236
<>
@@ -2303,7 +2264,7 @@ describe('ReactSuspenseList', () => {
2264
2265
ReactNoop.render(<Foo />);
2266
2306
- expect(Scheduler).toFlushAndYield(['A', 'B', '-']);
2267
+ await waitForAll(['A', 'B', '-']);
2268
2269
expect(ReactNoop).toMatchRenderedOutput(
2270
<div>
@@ -2316,7 +2277,7 @@ describe('ReactSuspenseList', () => {
2277
// Update the row adjacent to the list
2278
act(() => updateAdjacent('C'));
2279
2319
- expect(Scheduler).toHaveYielded(['C']);
2280
+ assertLog(['C']);
2281
2282
expect(ReactNoop).toMatchRenderedOutput(
2283
<div>
@@ -2359,7 +2320,7 @@ describe('ReactSuspenseList', () => {
2320
2321
ReactNoop.render(<Foo />);
2322
2362
- expect(Scheduler).toFlushAndYield(['A', 'Sync B']);
2323
+ await waitForAll(['A', 'Sync B']);
2324
2325
expect(ReactNoop).toMatchRenderedOutput(
2326
<>
@@ -2373,7 +2334,7 @@ describe('ReactSuspenseList', () => {
2334
// During an update we suspend on B.
2335
act(() => setAsyncB(true));
2336
2376
- expect(Scheduler).toHaveYielded([
2337
+ assertLog([
2338
'Suspend! [B]',
2339
'Loading B',
2340
// The second pass is the "force hide" pass
@@ -2391,7 +2352,7 @@ describe('ReactSuspenseList', () => {
2352
// This should leave the tree intact.
2353
act(() => ReactNoop.render(<Foo updateList={true} />));
2354
2394
- expect(Scheduler).toHaveYielded(['A', 'Suspend! [B]', 'Loading B']);
2355
+ assertLog(['A', 'Suspend! [B]', 'Loading B']);
2356
2357
expect(ReactNoop).toMatchRenderedOutput(
2358
<>
@@ -2402,7 +2363,7 @@ describe('ReactSuspenseList', () => {
2363
2364
await AsyncB.resolve();
2365
2405
- expect(Scheduler).toFlushAndYield(['B']);
2366
+ await waitForAll(['B']);
2367
2368
expect(ReactNoop).toMatchRenderedOutput(
2369
<>
@@ -2448,7 +2409,7 @@ describe('ReactSuspenseList', () => {
2409
2410
ReactNoop.render(<Foo />);
2411
2451
- expect(Scheduler).toFlushAndYield(['A', 'Sync B']);
2412
+ await waitForAll(['A', 'Sync B']);
2413
2414
expect(ReactNoop).toMatchRenderedOutput(
2415
<>
@@ -2462,7 +2423,7 @@ describe('ReactSuspenseList', () => {
2423
// During an update we suspend on B.
2424
act(() => setAsyncB(true));
2425
2465
- expect(Scheduler).toHaveYielded([
2426
+ assertLog([
2427
'Suspend! [B]',
2428
'Loading B',
2429
// The second pass is the "force hide" pass
@@ -2480,7 +2441,7 @@ describe('ReactSuspenseList', () => {
2441
// This should leave the tree intact.
2442
act(() => ReactNoop.render(<Foo updateList={true} />));
2443
2483
- expect(Scheduler).toHaveYielded(['A', 'Suspend! [B]', 'Loading B']);
2444
+ assertLog(['A', 'Suspend! [B]', 'Loading B']);
2445
2446
expect(ReactNoop).toMatchRenderedOutput(
2447
<>
@@ -2491,7 +2452,7 @@ describe('ReactSuspenseList', () => {
2452
2453
await AsyncB.resolve();
2454
2494
- expect(Scheduler).toFlushAndYield(['B']);
2455
+ await waitForAll(['B']);
2456
2457
expect(ReactNoop).toMatchRenderedOutput(
2458
<>
@@ -2535,7 +2496,7 @@ describe('ReactSuspenseList', () => {
2496
2497
ReactNoop.render(<Foo />);
2498
2538
- expect(Scheduler).toFlushAndYield([]);
2499
+ await waitForAll([]);
2500
2501
expect(ReactNoop).toMatchRenderedOutput(null);
2502
@@ -2544,13 +2505,13 @@ describe('ReactSuspenseList', () => {
2505
updateLowPri(true);
2506
});
2507
// Flush partially through.
2547
- expect(Scheduler).toFlushAndYieldThrough(['B', 'C']);
2508
+ await waitFor(['B', 'C']);
2509
2510
// Schedule another update at higher priority.
2511
ReactNoop.flushSync(() => updateHighPri(true));
2512
2513
// That will intercept the previous render.
2553
- expect(Scheduler).toHaveYielded([
2514
+ assertLog([
2515
'Suspend! [A]',
2516
'Loading A',
2517
// Re-render at forced.
@@ -2560,13 +2521,13 @@ describe('ReactSuspenseList', () => {
2521
expect(ReactNoop).toMatchRenderedOutput(<span>Loading A</span>);
2522
2523
// Try again on low-pri.
2563
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading A']);
2524
+ await waitForAll(['Suspend! [A]', 'Loading A']);
2525
expect(ReactNoop).toMatchRenderedOutput(<span>Loading A</span>);
2526
});
2527
2528
await AsyncA.resolve();
2529
2569
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C', 'D']);
2530
+ await waitForAll(['A', 'B', 'C', 'D']);
2531
2532
expect(ReactNoop).toMatchRenderedOutput(
2533
<>
@@ -2612,7 +2573,7 @@ describe('ReactSuspenseList', () => {
2573
2574
ReactNoop.render(<Foo />);
2575
2615
- expect(Scheduler).toFlushAndYield([
2576
+ await waitForAll([
2577
'A',
2578
'Suspend! [B]',
2579
'Loading B',
@@ -2631,7 +2592,7 @@ describe('ReactSuspenseList', () => {
2592
2593
ReactNoop.render(<Foo />);
2594
2634
- expect(Scheduler).toFlushAndYield(['A', 'B']);
2595
+ await waitForAll(['A', 'B']);
2596
2597
expect(ReactNoop).toMatchRenderedOutput(
2598
<>
@@ -2681,15 +2642,10 @@ describe('ReactSuspenseList', () => {
2642
React.startTransition(() => {
2643
ReactNoop.render(<App />);
2644
});
2684
- expect(Scheduler).toFlushAndYieldThrough([
2685
- 'App',
2686
- 'First Pass A',
2687
- 'Mount A',
2688
- 'A',
2689
- ]);
2645
+ await waitFor(['App', 'First Pass A', 'Mount A', 'A']);
2646
expect(ReactNoop).toMatchRenderedOutput(<span>A</span>);
2647
2692
- expect(Scheduler).toFlushAndYieldThrough(['First Pass B', 'Mount B', 'B']);
2648
+ await waitFor(['First Pass B', 'Mount B', 'B']);
2649
expect(ReactNoop).toMatchRenderedOutput(
2650
<>
2651
<span>A</span>
@@ -2697,7 +2653,7 @@ describe('ReactSuspenseList', () => {
2653
</>,
2654
);
2655
2700
- expect(Scheduler).toFlushAndYield(['C']);
2656
+ await waitForAll(['C']);
2657
expect(ReactNoop).toMatchRenderedOutput(
2658
<>
2659
<span>A</span>
@@ -2749,7 +2705,7 @@ describe('ReactSuspenseList', () => {
2705
React.startTransition(() => {
2706
ReactNoop.render(<App />);
2707
});
2752
- expect(Scheduler).toFlushAndYieldThrough([
2708
+ await waitFor([
2709
'App',
2710
'First Pass A',
2711
'Loading B',
@@ -2765,7 +2721,7 @@ describe('ReactSuspenseList', () => {
2721
</>,
2722
);
2723
2768
- expect(Scheduler).toFlushAndYieldThrough(['First Pass B', 'Mount B', 'B']);
2724
+ await waitFor(['First Pass B', 'Mount B', 'B']);
2725
expect(ReactNoop).toMatchRenderedOutput(
2726
<>
2727
<span>A</span>
@@ -2774,7 +2730,7 @@ describe('ReactSuspenseList', () => {
2730
</>,
2731
);
2732
2777
- expect(Scheduler).toFlushAndYield(['C']);
2733
+ await waitForAll(['C']);
2734
expect(ReactNoop).toMatchRenderedOutput(
2735
<>
2736
<span>A</span>
@@ -2840,13 +2796,7 @@ describe('ReactSuspenseList', () => {
2796
2797
ReactNoop.render(<App suspendTail={true} />);
2798
2843
- expect(Scheduler).toFlushAndYield([
2844
- 'App',
2845
- 'A',
2846
- 'B',
2847
- 'Suspend! [C]',
2848
- 'Fallback',
2849
- ]);
2799
+ await waitForAll(['App', 'A', 'B', 'Suspend! [C]', 'Fallback']);
2800
expect(ReactNoop).toMatchRenderedOutput(
2801
<>
2802
<span>A</span>
@@ -2868,7 +2818,7 @@ describe('ReactSuspenseList', () => {
2818
2819
ReactNoop.render(<App suspendTail={false} />);
2820
2871
- expect(Scheduler).toFlushAndYield(['App', 'A', 'B', 'C']);
2821
+ await waitForAll(['App', 'A', 'B', 'C']);
2822
2823
expect(ReactNoop).toMatchRenderedOutput(
2824
<>
@@ -2886,7 +2836,7 @@ describe('ReactSuspenseList', () => {
2836
2837
ReactNoop.render(<App addRow={true} suspendTail={true} />);
2838
2889
- expect(Scheduler).toFlushAndYield([
2839
+ await waitForAll([
2840
'App',
2841
'A',
2842
'B',
@@ -2928,7 +2878,7 @@ describe('ReactSuspenseList', () => {
2878
2879
await C.resolve();
2880
2931
- expect(Scheduler).toFlushAndYield(['C', 'Suspend! [D]']);
2881
+ await waitForAll(['C', 'Suspend! [D]']);
2882
expect(ReactNoop).toMatchRenderedOutput(
2883
<>
2884
<span>A</span>
@@ -3003,12 +2953,7 @@ describe('ReactSuspenseList', () => {
2953
2954
ReactNoop.render(<Foo />);
2955
3006
- expect(Scheduler).toFlushAndYield([
3007
- 'Suspend! [A]',
3008
- 'Loading A',
3009
- 'Loading B',
3010
- 'Loading C',
3011
- ]);
2956
+ await waitForAll(['Suspend! [A]', 'Loading A', 'Loading B', 'Loading C']);
2957
2958
expect(ReactNoop).toMatchRenderedOutput(
2959
<>
@@ -3020,7 +2965,7 @@ describe('ReactSuspenseList', () => {
2965
2966
await A.resolve();
2967
3023
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]']);
2968
+ await waitForAll(['A', 'Suspend! [B]']);
2969
2970
expect(ReactNoop).toMatchRenderedOutput(
2971
<>
@@ -3032,7 +2977,7 @@ describe('ReactSuspenseList', () => {
2977
2978
await B.resolve();
2979
3035
- expect(Scheduler).toFlushAndYield(['B', 'C']);
2980
+ await waitForAll(['B', 'C']);
2981
2982
expect(ReactNoop).toMatchRenderedOutput(
2983
<>
packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js
+47
-60
@@ -17,6 +17,8 @@ let ReactCache;
17
let Suspense;
18
let TextResource;
19
let textResourceShouldFail;
20
+let waitForAll;
21
+let assertLog;
22
23
describe('ReactSuspensePlaceholder', () => {
24
beforeEach(() => {
@@ -34,6 +36,10 @@ describe('ReactSuspensePlaceholder', () => {
36
Profiler = React.Profiler;
37
Suspense = React.Suspense;
38
39
+ const InternalTestUtils = require('internal-test-utils');
40
+ waitForAll = InternalTestUtils.waitForAll;
41
+ assertLog = InternalTestUtils.assertLog;
42
+
43
TextResource = ReactCache.unstable_createResource(
44
([text, ms = 0]) => {
45
let listeners = null;
@@ -106,7 +112,7 @@ describe('ReactSuspensePlaceholder', () => {
112
}
113
}
114
109
- it('times out children that are already hidden', () => {
115
+ it('times out children that are already hidden', async () => {
116
class HiddenText extends React.PureComponent {
117
render() {
118
const text = this.props.text;
@@ -132,13 +138,13 @@ describe('ReactSuspensePlaceholder', () => {
138
// Initial mount
139
ReactNoop.render(<App middleText="B" />);
140
135
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'C', 'Loading...']);
141
+ await waitForAll(['A', 'Suspend! [B]', 'C', 'Loading...']);
142
expect(ReactNoop).toMatchRenderedOutput('Loading...');
143
144
jest.advanceTimersByTime(1000);
139
- expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
145
+ assertLog(['Promise resolved [B]']);
146
141
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
147
+ await waitForAll(['A', 'B', 'C']);
148
149
expect(ReactNoop).toMatchRenderedOutput(
150
<>
@@ -150,11 +156,11 @@ describe('ReactSuspensePlaceholder', () => {
156
157
// Update
158
ReactNoop.render(<App middleText="B2" />);
153
- expect(Scheduler).toFlushAndYield(['Suspend! [B2]', 'C', 'Loading...']);
159
+ await waitForAll(['Suspend! [B2]', 'C', 'Loading...']);
160
161
// Time out the update
162
jest.advanceTimersByTime(750);
157
- expect(Scheduler).toFlushAndYield([]);
163
+ await waitForAll([]);
164
expect(ReactNoop).toMatchRenderedOutput(
165
<>
166
<span hidden={true}>A</span>
@@ -166,8 +172,8 @@ describe('ReactSuspensePlaceholder', () => {
172
173
// Resolve the promise
174
jest.advanceTimersByTime(1000);
169
- expect(Scheduler).toHaveYielded(['Promise resolved [B2]']);
170
- expect(Scheduler).toFlushAndYield(['B2', 'C']);
175
+ assertLog(['Promise resolved [B2]']);
176
+ await waitForAll(['B2', 'C']);
177
178
// Render the final update. A should still be hidden, because it was
179
// given a `hidden` prop.
@@ -194,39 +200,34 @@ describe('ReactSuspensePlaceholder', () => {
200
// Initial mount
201
ReactNoop.render(<App middleText="B" />);
202
197
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'C', 'Loading...']);
203
+ await waitForAll(['A', 'Suspend! [B]', 'C', 'Loading...']);
204
205
expect(ReactNoop).not.toMatchRenderedOutput('ABC');
206
207
jest.advanceTimersByTime(1000);
202
- expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
203
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
208
+ assertLog(['Promise resolved [B]']);
209
+ await waitForAll(['A', 'B', 'C']);
210
expect(ReactNoop).toMatchRenderedOutput('ABC');
211
212
// Update
213
ReactNoop.render(<App middleText="B2" />);
208
- expect(Scheduler).toFlushAndYield([
209
- 'A',
210
- 'Suspend! [B2]',
211
- 'C',
212
- 'Loading...',
213
- ]);
214
+ await waitForAll(['A', 'Suspend! [B2]', 'C', 'Loading...']);
215
// Time out the update
216
jest.advanceTimersByTime(750);
216
- expect(Scheduler).toFlushAndYield([]);
217
+ await waitForAll([]);
218
expect(ReactNoop).toMatchRenderedOutput('Loading...');
219
220
// Resolve the promise
221
jest.advanceTimersByTime(1000);
221
- expect(Scheduler).toHaveYielded(['Promise resolved [B2]']);
222
- expect(Scheduler).toFlushAndYield(['A', 'B2', 'C']);
222
+ assertLog(['Promise resolved [B2]']);
223
+ await waitForAll(['A', 'B2', 'C']);
224
225
// Render the final update. A should still be hidden, because it was
226
// given a `hidden` prop.
227
expect(ReactNoop).toMatchRenderedOutput('AB2C');
228
});
229
229
- it('preserves host context for text nodes', () => {
230
+ it('preserves host context for text nodes', async () => {
231
function App(props) {
232
return (
233
// uppercase is a special type that causes React Noop to render child
@@ -244,32 +245,27 @@ describe('ReactSuspensePlaceholder', () => {
245
// Initial mount
246
ReactNoop.render(<App middleText="b" />);
247
247
- expect(Scheduler).toFlushAndYield(['a', 'Suspend! [b]', 'c', 'Loading...']);
248
+ await waitForAll(['a', 'Suspend! [b]', 'c', 'Loading...']);
249
250
expect(ReactNoop).toMatchRenderedOutput(<uppercase>LOADING...</uppercase>);
251
252
jest.advanceTimersByTime(1000);
252
- expect(Scheduler).toHaveYielded(['Promise resolved [b]']);
253
- expect(Scheduler).toFlushAndYield(['a', 'b', 'c']);
253
+ assertLog(['Promise resolved [b]']);
254
+ await waitForAll(['a', 'b', 'c']);
255
expect(ReactNoop).toMatchRenderedOutput(<uppercase>ABC</uppercase>);
256
257
// Update
258
ReactNoop.render(<App middleText="b2" />);
258
- expect(Scheduler).toFlushAndYield([
259
- 'a',
260
- 'Suspend! [b2]',
261
- 'c',
262
- 'Loading...',
263
- ]);
259
+ await waitForAll(['a', 'Suspend! [b2]', 'c', 'Loading...']);
260
// Time out the update
261
jest.advanceTimersByTime(750);
266
- expect(Scheduler).toFlushAndYield([]);
262
+ await waitForAll([]);
263
expect(ReactNoop).toMatchRenderedOutput(<uppercase>LOADING...</uppercase>);
264
265
// Resolve the promise
266
jest.advanceTimersByTime(1000);
271
- expect(Scheduler).toHaveYielded(['Promise resolved [b2]']);
272
- expect(Scheduler).toFlushAndYield(['a', 'b2', 'c']);
267
+ assertLog(['Promise resolved [b2]']);
268
+ await waitForAll(['a', 'b2', 'c']);
269
270
// Render the final update. A should still be hidden, because it was
271
// given a `hidden` prop.
@@ -312,7 +308,7 @@ describe('ReactSuspensePlaceholder', () => {
308
describe('when suspending during mount', () => {
309
it('properly accounts for base durations when a suspended times out in a legacy tree', async () => {
310
ReactNoop.renderLegacySyncRoot(<App shouldSuspend={true} />);
315
- expect(Scheduler).toHaveYielded([
311
+ assertLog([
312
'App',
313
'Suspending',
314
'Suspend! [Loaded]',
@@ -330,11 +326,11 @@ describe('ReactSuspensePlaceholder', () => {
326
327
jest.advanceTimersByTime(1000);
328
333
- expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
329
+ assertLog(['Promise resolved [Loaded]']);
330
331
ReactNoop.flushSync();
332
337
- expect(Scheduler).toHaveYielded(['Loaded']);
333
+ assertLog(['Loaded']);
334
expect(ReactNoop).toMatchRenderedOutput('LoadedText');
335
expect(onRender).toHaveBeenCalledTimes(2);
336
@@ -345,10 +341,10 @@ describe('ReactSuspensePlaceholder', () => {
341
expect(onRender.mock.calls[1][3]).toBe(8);
342
});
343
348
- it('properly accounts for base durations when a suspended times out in a concurrent tree', () => {
344
+ it('properly accounts for base durations when a suspended times out in a concurrent tree', async () => {
345
ReactNoop.render(<App shouldSuspend={true} />);
346
351
- expect(Scheduler).toFlushAndYield([
347
+ await waitForAll([
348
'App',
349
'Suspending',
350
'Suspend! [Loaded]',
@@ -368,8 +364,8 @@ describe('ReactSuspensePlaceholder', () => {
364
365
// Resolve the pending promise.
366
jest.advanceTimersByTime(1000);
371
- expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
372
- expect(Scheduler).toFlushAndYield(['Suspending', 'Loaded', 'Text']);
367
+ assertLog(['Promise resolved [Loaded]']);
368
+ await waitForAll(['Suspending', 'Loaded', 'Text']);
369
expect(ReactNoop).toMatchRenderedOutput('LoadedText');
370
expect(onRender).toHaveBeenCalledTimes(2);
371
@@ -385,7 +381,7 @@ describe('ReactSuspensePlaceholder', () => {
381
ReactNoop.renderLegacySyncRoot(
382
<App shouldSuspend={false} textRenderDuration={5} />,
383
);
388
- expect(Scheduler).toHaveYielded(['App', 'Text']);
384
+ assertLog(['App', 'Text']);
385
expect(ReactNoop).toMatchRenderedOutput('Text');
386
expect(onRender).toHaveBeenCalledTimes(1);
387
@@ -395,7 +391,7 @@ describe('ReactSuspensePlaceholder', () => {
391
expect(onRender.mock.calls[0][3]).toBe(5);
392
393
ReactNoop.render(<App shouldSuspend={true} textRenderDuration={5} />);
398
- expect(Scheduler).toHaveYielded([
394
+ assertLog([
395
'App',
396
'Suspending',
397
'Suspend! [Loaded]',
@@ -415,7 +411,7 @@ describe('ReactSuspensePlaceholder', () => {
411
ReactNoop.renderLegacySyncRoot(
412
<App shouldSuspend={true} text="New" textRenderDuration={6} />,
413
);
418
- expect(Scheduler).toHaveYielded([
414
+ assertLog([
415
'App',
416
'Suspending',
417
'Suspend! [Loaded]',
@@ -429,11 +425,11 @@ describe('ReactSuspensePlaceholder', () => {
425
expect(onRender.mock.calls[1][3]).toBe(10);
426
jest.advanceTimersByTime(1000);
427
432
- expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
428
+ assertLog(['Promise resolved [Loaded]']);
429
430
ReactNoop.flushSync();
431
436
- expect(Scheduler).toHaveYielded(['Loaded']);
432
+ assertLog(['Loaded']);
433
expect(ReactNoop).toMatchRenderedOutput('LoadedNew');
434
expect(onRender).toHaveBeenCalledTimes(4);
435
@@ -444,7 +440,7 @@ describe('ReactSuspensePlaceholder', () => {
440
expect(onRender.mock.calls[3][3]).toBe(9);
441
});
442
447
- it('properly accounts for base durations when a suspended times out in a concurrent tree', () => {
443
+ it('properly accounts for base durations when a suspended times out in a concurrent tree', async () => {
444
ReactNoop.render(
445
<>
446
<App shouldSuspend={false} textRenderDuration={5} />
@@ -452,7 +448,7 @@ describe('ReactSuspensePlaceholder', () => {
448
</>,
449
);
450
455
- expect(Scheduler).toFlushAndYield(['App', 'Text']);
451
+ await waitForAll(['App', 'Text']);
452
expect(ReactNoop).toMatchRenderedOutput('Text');
453
expect(onRender).toHaveBeenCalledTimes(1);
454
@@ -467,7 +463,7 @@ describe('ReactSuspensePlaceholder', () => {
463
<Suspense fallback={null} />
464
</>,
465
);
470
- expect(Scheduler).toFlushAndYield([
466
+ await waitForAll([
467
'App',
468
'Suspending',
469
'Suspend! [Loaded]',
@@ -507,7 +503,7 @@ describe('ReactSuspensePlaceholder', () => {
503
// from timers.
504
Scheduler.unstable_advanceTime(100);
505
510
- expect(Scheduler).toFlushAndYield([
506
+ await waitForAll([
507
'App',
508
'Suspending',
509
'Suspend! [Loaded]',
@@ -520,17 +516,8 @@ describe('ReactSuspensePlaceholder', () => {
516
517
// Resolve the pending promise.
518
jest.advanceTimersByTime(100);
523
- expect(Scheduler).toHaveYielded([
524
- 'Promise resolved [Loaded]',
525
- 'Promise resolved [Sibling]',
526
- ]);
527
- expect(Scheduler).toFlushAndYield([
528
- 'App',
529
- 'Suspending',
530
- 'Loaded',
531
- 'New',
532
- 'Sibling',
533
- ]);
519
+ assertLog(['Promise resolved [Loaded]', 'Promise resolved [Sibling]']);
520
+ await waitForAll(['App', 'Suspending', 'Loaded', 'New', 'Sibling']);
521
expect(onRender).toHaveBeenCalledTimes(3);
522
523
// When the suspending data is resolved and our final UI is rendered,
packages/react-reconciler/src/__tests__/ReactThenable-test.js
+63
-87
@@ -12,6 +12,10 @@ let Suspense;
12
let startTransition;
13
let cache;
14
let pendingTextRequests;
15
+let waitFor;
16
+let waitForPaint;
17
+let assertLog;
18
+let waitForAll;
19
20
describe('ReactThenable', () => {
21
beforeEach(() => {
@@ -29,6 +33,12 @@ describe('ReactThenable', () => {
33
startTransition = React.startTransition;
34
cache = React.cache;
35
36
+ const InternalTestUtils = require('internal-test-utils');
37
+ waitForAll = InternalTestUtils.waitForAll;
38
+ assertLog = InternalTestUtils.assertLog;
39
+ waitForPaint = InternalTestUtils.waitForPaint;
40
+ waitFor = InternalTestUtils.waitFor;
41
+
42
pendingTextRequests = new Map();
43
});
44
@@ -94,7 +104,7 @@ describe('ReactThenable', () => {
104
});
105
});
106
97
- expect(Scheduler).toHaveYielded([
107
+ assertLog([
108
// React will yield when the async component suspends.
109
'Suspend!',
110
'Resolve in microtask',
@@ -128,11 +138,7 @@ describe('ReactThenable', () => {
138
root.render(<App />);
139
});
140
});
131
- expect(Scheduler).toHaveYielded([
132
- 'Suspend!',
133
- 'Resolve in microtask',
134
- 'Async',
135
- ]);
141
+ assertLog(['Suspend!', 'Resolve in microtask', 'Async']);
142
expect(root).toMatchRenderedOutput('Async');
143
});
144
@@ -172,7 +178,7 @@ describe('ReactThenable', () => {
178
await act(async () => {
179
root.render(<App />);
180
});
175
- expect(Scheduler).toHaveYielded(['Suspend!', 'Loading...']);
181
+ assertLog(['Suspend!', 'Loading...']);
182
expect(root).toMatchRenderedOutput('Loading...');
183
});
184
@@ -201,7 +207,7 @@ describe('ReactThenable', () => {
207
root.render(<App />);
208
});
209
});
204
- expect(Scheduler).toHaveYielded(['ABC']);
210
+ assertLog(['ABC']);
211
expect(root).toMatchRenderedOutput('ABC');
212
});
213
@@ -229,7 +235,7 @@ describe('ReactThenable', () => {
235
root.render(<App />);
236
});
237
});
232
- expect(Scheduler).toHaveYielded(['ABC']);
238
+ assertLog(['ABC']);
239
expect(root).toMatchRenderedOutput('ABC');
240
});
241
@@ -275,7 +281,7 @@ describe('ReactThenable', () => {
281
root.render(<App />);
282
});
283
});
278
- expect(Scheduler).toHaveYielded(['Oops!', 'Oops!']);
284
+ assertLog(['Oops!', 'Oops!']);
285
});
286
287
// @gate enableUseHook
@@ -308,7 +314,7 @@ describe('ReactThenable', () => {
314
root.render(<App />);
315
});
316
});
311
- expect(Scheduler).toHaveYielded(['ABCD']);
317
+ assertLog(['ABCD']);
318
expect(root).toMatchRenderedOutput('ABCD');
319
});
320
@@ -344,7 +350,7 @@ describe('ReactThenable', () => {
350
root.render(<App />);
351
});
352
});
347
- expect(Scheduler).toHaveYielded(['CD', 'Loading...']);
353
+ assertLog(['CD', 'Loading...']);
354
expect(root).toMatchRenderedOutput('Loading...');
355
});
356
@@ -397,7 +403,7 @@ describe('ReactThenable', () => {
403
root.render(<App />);
404
});
405
});
400
- expect(Scheduler).toHaveYielded([
406
+ assertLog([
407
// First attempt. The uncached promise suspends.
408
'Suspend! [Async]',
409
// Because the promise already fulfilled, we're able to unwrap the value
@@ -427,7 +433,7 @@ describe('ReactThenable', () => {
433
});
434
435
// @gate enableUseHook
430
- test('basic use(context)', () => {
436
+ test('basic use(context)', async () => {
437
const ContextA = React.createContext('');
438
const ContextB = React.createContext('B');
439
@@ -446,7 +452,7 @@ describe('ReactThenable', () => {
452
453
const root = ReactNoop.createRoot();
454
root.render(<App />);
449
- expect(Scheduler).toFlushWithoutYielding();
455
+ await waitForAll([]);
456
expect(root).toMatchRenderedOutput('AB');
457
});
458
@@ -482,7 +488,7 @@ describe('ReactThenable', () => {
488
startTransition(() => {
489
root.render(<App text="world" />);
490
});
485
- expect(Scheduler).toFlushUntilNextPaint([]);
491
+ await waitForPaint([]);
492
expect(root).toMatchRenderedOutput(null);
493
494
await resolve({default: <Text key="hi" text="Hello " />});
@@ -492,7 +498,7 @@ describe('ReactThenable', () => {
498
root.render(<App text="world!" />);
499
});
500
495
- expect(Scheduler).toHaveYielded(['Hello ', 'world!']);
501
+ assertLog(['Hello ', 'world!']);
502
503
expect(root).toMatchRenderedOutput(<div>Hello world!</div>);
504
});
@@ -547,7 +553,7 @@ describe('ReactThenable', () => {
553
</Suspense>,
554
);
555
});
550
- expect(Scheduler).toHaveYielded(['(empty)']);
556
+ assertLog(['(empty)']);
557
expect(root).toMatchRenderedOutput('(empty)');
558
559
await act(async () => {
@@ -559,13 +565,13 @@ describe('ReactThenable', () => {
565
);
566
});
567
});
562
- expect(Scheduler).toHaveYielded(['Async text requested [Async]']);
568
+ assertLog(['Async text requested [Async]']);
569
expect(root).toMatchRenderedOutput('(empty)');
570
571
await act(async () => {
572
resolveTextRequests('Async');
573
});
568
- expect(Scheduler).toHaveYielded(['Async text requested [Async]', 'Async']);
574
+ assertLog(['Async text requested [Async]', 'Async']);
575
expect(root).toMatchRenderedOutput('Async');
576
});
577
@@ -586,10 +592,7 @@ describe('ReactThenable', () => {
592
});
593
});
594
// Even though the initial render was a transition, it shows a fallback.
589
- expect(Scheduler).toHaveYielded([
590
- 'Async text requested [Async]',
591
- 'Loading...',
592
- ]);
595
+ assertLog(['Async text requested [Async]', 'Loading...']);
596
expect(root).toMatchRenderedOutput('Loading...');
597
598
// Resolve the original data
@@ -603,7 +606,7 @@ describe('ReactThenable', () => {
606
// this test, how would the developer be able to imperatively flush it if it
607
// wasn't initiated until the current `act` call? Can't think of a better
608
// strategy at the moment.
606
- expect(Scheduler).toHaveYielded(['Async text requested [Async]']);
609
+ assertLog(['Async text requested [Async]']);
610
expect(root).toMatchRenderedOutput('Loading...');
611
612
// Flush the second request.
@@ -611,7 +614,7 @@ describe('ReactThenable', () => {
614
resolveTextRequests('Async');
615
});
616
// This time it finishes because it was during a retry.
614
- expect(Scheduler).toHaveYielded(['Async text requested [Async]', 'Async']);
617
+ assertLog(['Async text requested [Async]', 'Async']);
618
expect(root).toMatchRenderedOutput('Async');
619
});
620
@@ -635,9 +638,7 @@ describe('ReactThenable', () => {
638
);
639
});
640
});
638
- expect(Scheduler).toHaveYielded([
639
- 'Async text requested [Will never resolve]',
640
- ]);
641
+ assertLog(['Async text requested [Will never resolve]']);
642
643
await act(async () => {
644
root.render(
@@ -646,7 +647,7 @@ describe('ReactThenable', () => {
647
</Suspense>,
648
);
649
});
649
- expect(Scheduler).toHaveYielded(['Something different']);
650
+ assertLog(['Something different']);
651
});
652
653
// @gate enableUseHook
@@ -669,9 +670,7 @@ describe('ReactThenable', () => {
670
);
671
});
672
});
672
- expect(Scheduler).toHaveYielded([
673
- 'Async text requested [Will never resolve]',
674
- ]);
673
+ assertLog(['Async text requested [Will never resolve]']);
674
675
// Calling a hook should error because we're oustide of a component.
676
expect(useState).toThrow(
@@ -704,7 +703,7 @@ describe('ReactThenable', () => {
703
ReactNoop.flushSync(() => {
704
root.render(<App />);
705
});
707
- expect(Scheduler).toHaveYielded(['Hi']);
706
+ assertLog(['Hi']);
707
expect(root).toMatchRenderedOutput('Hi');
708
});
709
@@ -745,26 +744,21 @@ describe('ReactThenable', () => {
744
await act(() => {
745
root.render(<Parent />);
746
});
748
- expect(Scheduler).toHaveYielded([
749
- 'childShouldSuspend: false, showChild: true',
750
- 'Child',
751
- ]);
747
+ assertLog(['childShouldSuspend: false, showChild: true', 'Child']);
748
expect(root).toMatchRenderedOutput('Child');
749
754
- await act(() => {
750
+ await act(async () => {
751
// Perform an update that causes the app to suspend
752
startTransition(() => {
753
setChildShouldSuspend(true);
754
});
759
- expect(Scheduler).toFlushAndYieldThrough([
760
- 'childShouldSuspend: true, showChild: true',
761
- ]);
755
+ await waitFor(['childShouldSuspend: true, showChild: true']);
756
// While the update is in progress, schedule another update.
757
startTransition(() => {
758
setShowChild(false);
759
});
760
});
767
- expect(Scheduler).toHaveYielded([
761
+ assertLog([
762
// Because the interleaved update is not higher priority than what we were
763
// already working on, it won't interrupt. The first update will continue,
764
// and will suspend.
@@ -827,17 +821,14 @@ describe('ReactThenable', () => {
821
});
822
});
823
// Suspends while we wait for the async service to respond.
830
- expect(Scheduler).toHaveYielded([
831
- 'Compute uppercase: Hello',
832
- 'Async text requested [HELLO!]',
833
- ]);
824
+ assertLog(['Compute uppercase: Hello', 'Async text requested [HELLO!]']);
825
expect(root).toMatchRenderedOutput(null);
826
827
// The data is received.
828
await act(async () => {
829
resolveTextRequests('HELLO!');
830
});
840
- expect(Scheduler).toHaveYielded([
831
+ assertLog([
832
// We shouldn't run the uppercase computation again, because we can reuse
833
// the computation from the previous attempt.
834
// 'Compute uppercase: Hello',
@@ -867,15 +858,12 @@ describe('ReactThenable', () => {
858
root.render(<Kitchen />);
859
});
860
});
870
- expect(Scheduler).toHaveYielded(['Async text requested [apple]']);
861
+ assertLog(['Async text requested [apple]']);
862
expect(root).toMatchRenderedOutput(null);
863
await act(async () => {
864
resolveTextRequests('apple');
865
});
875
- expect(Scheduler).toHaveYielded([
876
- 'Async text requested [apple]',
877
- 'apple carrot',
878
- ]);
866
+ assertLog(['Async text requested [apple]', 'apple carrot']);
867
expect(root).toMatchRenderedOutput('apple carrot');
868
869
// Update the state variable after the use().
@@ -884,15 +872,12 @@ describe('ReactThenable', () => {
872
_setVegetable('dill');
873
});
874
});
887
- expect(Scheduler).toHaveYielded(['Async text requested [apple]']);
875
+ assertLog(['Async text requested [apple]']);
876
expect(root).toMatchRenderedOutput('apple carrot');
877
await act(async () => {
878
resolveTextRequests('apple');
879
});
892
- expect(Scheduler).toHaveYielded([
893
- 'Async text requested [apple]',
894
- 'apple dill',
895
- ]);
880
+ assertLog(['Async text requested [apple]', 'apple dill']);
881
expect(root).toMatchRenderedOutput('apple dill');
882
883
// Update the state variable before the use(). The second state is maintained.
@@ -901,15 +886,12 @@ describe('ReactThenable', () => {
886
_setFruit('banana');
887
});
888
});
904
- expect(Scheduler).toHaveYielded(['Async text requested [banana]']);
889
+ assertLog(['Async text requested [banana]']);
890
expect(root).toMatchRenderedOutput('apple dill');
891
await act(async () => {
892
resolveTextRequests('banana');
893
});
909
- expect(Scheduler).toHaveYielded([
910
- 'Async text requested [banana]',
911
- 'banana dill',
912
- ]);
894
+ assertLog(['Async text requested [banana]', 'banana dill']);
895
expect(root).toMatchRenderedOutput('banana dill');
896
});
897
@@ -931,15 +913,12 @@ describe('ReactThenable', () => {
913
root.render(<Lexicon />);
914
});
915
});
934
- expect(Scheduler).toHaveYielded(['Async text requested [aguacate]']);
916
+ assertLog(['Async text requested [aguacate]']);
917
expect(root).toMatchRenderedOutput(null);
918
await act(async () => {
919
resolveTextRequests('aguacate');
920
});
939
- expect(Scheduler).toHaveYielded([
940
- 'Async text requested [aguacate]',
941
- 'aguacate abogado',
942
- ]);
921
+ assertLog(['Async text requested [aguacate]', 'aguacate abogado']);
922
expect(root).toMatchRenderedOutput('aguacate abogado');
923
924
// Now update the state.
@@ -948,15 +927,12 @@ describe('ReactThenable', () => {
927
_setLawyer('avocat');
928
});
929
});
951
- expect(Scheduler).toHaveYielded(['Async text requested [aguacate]']);
930
+ assertLog(['Async text requested [aguacate]']);
931
expect(root).toMatchRenderedOutput('aguacate abogado');
932
await act(async () => {
933
resolveTextRequests('aguacate');
934
});
956
- expect(Scheduler).toHaveYielded([
957
- 'Async text requested [aguacate]',
958
- 'aguacate avocat',
959
- ]);
935
+ assertLog(['Async text requested [aguacate]', 'aguacate avocat']);
936
expect(root).toMatchRenderedOutput('aguacate avocat');
937
});
938
@@ -977,13 +953,13 @@ describe('ReactThenable', () => {
953
root.render(<App text="Hello" />);
954
});
955
});
980
- expect(Scheduler).toHaveYielded(['Async text requested [Hello]']);
956
+ assertLog(['Async text requested [Hello]']);
957
expect(root).toMatchRenderedOutput(null);
958
959
await act(async () => {
960
resolveTextRequests('Hello');
961
});
986
- expect(Scheduler).toHaveYielded([
962
+ assertLog([
963
// We shouldn't request async text again, because the async function
964
// was memoized
965
// 'Async text requested [Hello]'
@@ -1015,7 +991,7 @@ describe('ReactThenable', () => {
991
</Suspense>,
992
);
993
});
1018
- expect(Scheduler).toHaveYielded([
994
+ assertLog([
995
'Async text requested [A]',
996
'Async text requested [B]',
997
'Async text requested [C]',
@@ -1028,19 +1004,19 @@ describe('ReactThenable', () => {
1004
await act(async () => {
1005
resolveTextRequests('A');
1006
});
1031
- expect(Scheduler).toHaveYielded(['A', '(Loading C...)', '(Loading B...)']);
1007
+ assertLog(['A', '(Loading C...)', '(Loading B...)']);
1008
expect(root).toMatchRenderedOutput('A(Loading B...)');
1009
1010
await act(async () => {
1011
resolveTextRequests('B');
1012
});
1037
- expect(Scheduler).toHaveYielded(['B', '(Loading C...)']);
1013
+ assertLog(['B', '(Loading C...)']);
1014
expect(root).toMatchRenderedOutput('AB(Loading C...)');
1015
1016
await act(async () => {
1017
resolveTextRequests('C');
1018
});
1043
- expect(Scheduler).toHaveYielded(['C']);
1019
+ assertLog(['C']);
1020
expect(root).toMatchRenderedOutput('ABC');
1021
});
1022
@@ -1068,7 +1044,7 @@ describe('ReactThenable', () => {
1044
</Suspense>,
1045
);
1046
});
1071
- expect(Scheduler).toHaveYielded([
1047
+ assertLog([
1048
'Async text requested [A]',
1049
'Async text requested [B]',
1050
'Async text requested [C]',
@@ -1081,13 +1057,13 @@ describe('ReactThenable', () => {
1057
await act(async () => {
1058
resolveTextRequests('A');
1059
});
1084
- expect(Scheduler).toHaveYielded(['Async text requested [A]']);
1060
+ assertLog(['Async text requested [A]']);
1061
expect(root).toMatchRenderedOutput('(Loading A...)');
1062
1063
await act(async () => {
1064
resolveTextRequests('A');
1065
});
1090
- expect(Scheduler).toHaveYielded([
1066
+ assertLog([
1067
// React suspends until A finishes loading.
1068
'Async text requested [A]',
1069
'A',
@@ -1106,13 +1082,13 @@ describe('ReactThenable', () => {
1082
await act(async () => {
1083
resolveTextRequests('B');
1084
});
1109
- expect(Scheduler).toHaveYielded(['Async text requested [B]']);
1085
+ assertLog(['Async text requested [B]']);
1086
expect(root).toMatchRenderedOutput('A(Loading B...)');
1087
1088
await act(async () => {
1089
resolveTextRequests('B');
1090
});
1115
- expect(Scheduler).toHaveYielded([
1091
+ assertLog([
1092
// React suspends until B finishes loading.
1093
'Async text requested [B]',
1094
'B',
@@ -1126,13 +1102,13 @@ describe('ReactThenable', () => {
1102
await act(async () => {
1103
resolveTextRequests('C');
1104
});
1129
- expect(Scheduler).toHaveYielded(['Async text requested [C]']);
1105
+ assertLog(['Async text requested [C]']);
1106
expect(root).toMatchRenderedOutput('AB(Loading C...)');
1107
1108
await act(async () => {
1109
resolveTextRequests('C');
1110
});
1135
- expect(Scheduler).toHaveYielded(['Async text requested [C]', 'C']);
1111
+ assertLog(['Async text requested [C]', 'C']);
1112
expect(root).toMatchRenderedOutput('ABC');
1113
});
1114
@@ -1162,7 +1138,7 @@ describe('ReactThenable', () => {
1138
root.render(<App />);
1139
});
1140
});
1165
- expect(Scheduler).toHaveYielded(['A1']);
1141
+ assertLog(['A1']);
1142
expect(root).toMatchRenderedOutput('A1');
1143
});
1144
});
packages/react-reconciler/src/__tests__/ReactTopLevelFragment-test.js
+19
-17
@@ -12,7 +12,7 @@
12
13
let React;
14
let ReactNoop;
15
-let Scheduler;
15
+let waitForAll;
16
17
// This is a new feature in Fiber so I put it in its own test file. It could
18
// probably move to one of the other test files once it is official.
@@ -21,18 +21,20 @@ describe('ReactTopLevelFragment', function () {
21
jest.resetModules();
22
React = require('react');
23
ReactNoop = require('react-noop-renderer');
24
- Scheduler = require('scheduler');
24
+
25
+ const InternalTestUtils = require('internal-test-utils');
26
+ waitForAll = InternalTestUtils.waitForAll;
27
});
28
27
- it('should render a simple fragment at the top of a component', function () {
29
+ it('should render a simple fragment at the top of a component', async function () {
30
function Fragment() {
31
return [<div key="a">Hello</div>, <div key="b">World</div>];
32
}
33
ReactNoop.render(<Fragment />);
32
- expect(Scheduler).toFlushWithoutYielding();
34
+ await waitForAll([]);
35
});
36
35
- it('should preserve state when switching from a single child', function () {
37
+ it('should preserve state when switching from a single child', async function () {
38
let instance = null;
39
40
class Stateful extends React.Component {
@@ -50,21 +52,21 @@ describe('ReactTopLevelFragment', function () {
52
);
53
}
54
ReactNoop.render(<Fragment />);
53
- expect(Scheduler).toFlushWithoutYielding();
55
+ await waitForAll([]);
56
57
const instanceA = instance;
58
59
expect(instanceA).not.toBe(null);
60
61
ReactNoop.render(<Fragment condition={true} />);
60
- expect(Scheduler).toFlushWithoutYielding();
62
+ await waitForAll([]);
63
64
const instanceB = instance;
65
66
expect(instanceB).toBe(instanceA);
67
});
68
67
- it('should not preserve state when switching to a nested array', function () {
69
+ it('should not preserve state when switching to a nested array', async function () {
70
let instance = null;
71
72
class Stateful extends React.Component {
@@ -82,21 +84,21 @@ describe('ReactTopLevelFragment', function () {
84
);
85
}
86
ReactNoop.render(<Fragment />);
85
- expect(Scheduler).toFlushWithoutYielding();
87
+ await waitForAll([]);
88
89
const instanceA = instance;
90
91
expect(instanceA).not.toBe(null);
92
93
ReactNoop.render(<Fragment condition={true} />);
92
- expect(Scheduler).toFlushWithoutYielding();
94
+ await waitForAll([]);
95
96
const instanceB = instance;
97
98
expect(instanceB).not.toBe(instanceA);
99
});
100
99
- it('preserves state if an implicit key slot switches from/to null', function () {
101
+ it('preserves state if an implicit key slot switches from/to null', async function () {
102
let instance = null;
103
104
class Stateful extends React.Component {
@@ -112,28 +114,28 @@ describe('ReactTopLevelFragment', function () {
114
: [<div key="b">Hello</div>, <Stateful key="a" />];
115
}
116
ReactNoop.render(<Fragment />);
115
- expect(Scheduler).toFlushWithoutYielding();
117
+ await waitForAll([]);
118
119
const instanceA = instance;
120
121
expect(instanceA).not.toBe(null);
122
123
ReactNoop.render(<Fragment condition={true} />);
122
- expect(Scheduler).toFlushWithoutYielding();
124
+ await waitForAll([]);
125
126
const instanceB = instance;
127
128
expect(instanceB).toBe(instanceA);
129
130
ReactNoop.render(<Fragment condition={false} />);
129
- expect(Scheduler).toFlushWithoutYielding();
131
+ await waitForAll([]);
132
133
const instanceC = instance;
134
135
expect(instanceC === instanceA).toBe(true);
136
});
137
136
- it('should preserve state in a reorder', function () {
138
+ it('should preserve state in a reorder', async function () {
139
let instance = null;
140
141
class Stateful extends React.Component {
@@ -149,14 +151,14 @@ describe('ReactTopLevelFragment', function () {
151
: [[<Stateful key="a" />, <div key="b">World</div>], <div key="c" />];
152
}
153
ReactNoop.render(<Fragment />);
152
- expect(Scheduler).toFlushWithoutYielding();
154
+ await waitForAll([]);
155
156
const instanceA = instance;
157
158
expect(instanceA).not.toBe(null);
159
160
ReactNoop.render(<Fragment condition={true} />);
159
- expect(Scheduler).toFlushWithoutYielding();
161
+ await waitForAll([]);
162
163
const instanceB = instance;
164
packages/react-reconciler/src/__tests__/ReactTopLevelText-test.js
+8
-6
@@ -12,7 +12,7 @@
12
13
let React;
14
let ReactNoop;
15
-let Scheduler;
15
+let waitForAll;
16
17
// This is a new feature in Fiber so I put it in its own test file. It could
18
// probably move to one of the other test files once it is official.
@@ -21,20 +21,22 @@ describe('ReactTopLevelText', () => {
21
jest.resetModules();
22
React = require('react');
23
ReactNoop = require('react-noop-renderer');
24
- Scheduler = require('scheduler');
24
+
25
+ const InternalTestUtils = require('internal-test-utils');
26
+ waitForAll = InternalTestUtils.waitForAll;
27
});
28
27
- it('should render a component returning strings directly from render', () => {
29
+ it('should render a component returning strings directly from render', async () => {
30
const Text = ({value}) => value;
31
ReactNoop.render(<Text value="foo" />);
30
- expect(Scheduler).toFlushWithoutYielding();
32
+ await waitForAll([]);
33
expect(ReactNoop).toMatchRenderedOutput('foo');
34
});
35
34
- it('should render a component returning numbers directly from render', () => {
36
+ it('should render a component returning numbers directly from render', async () => {
37
const Text = ({value}) => value;
38
ReactNoop.render(<Text value={10} />);
37
- expect(Scheduler).toFlushWithoutYielding();
39
+ await waitForAll([]);
40
expect(ReactNoop).toMatchRenderedOutput('10');
41
});
42
});
packages/react-reconciler/src/__tests__/ReactTransition-test.js
+51
-57
@@ -20,6 +20,10 @@ let useTransition;
20
let startTransition;
21
let act;
22
let getCacheForType;
23
+let waitForAll;
24
+let waitFor;
25
+let waitForPaint;
26
+let assertLog;
27
28
let caches;
29
let seededCache;
@@ -38,6 +42,12 @@ describe('ReactTransition', () => {
42
getCacheForType = React.unstable_getCacheForType;
43
act = require('jest-react').act;
44
45
+ const InternalTestUtils = require('internal-test-utils');
46
+ waitForAll = InternalTestUtils.waitForAll;
47
+ waitFor = InternalTestUtils.waitFor;
48
+ waitForPaint = InternalTestUtils.waitForPaint;
49
+ assertLog = InternalTestUtils.assertLog;
50
+
51
caches = [];
52
seededCache = null;
53
});
@@ -178,13 +188,13 @@ describe('ReactTransition', () => {
188
await act(async () => {
189
root.render(<App />);
190
});
181
- expect(Scheduler).toHaveYielded(['(empty)']);
191
+ assertLog(['(empty)']);
192
expect(root).toMatchRenderedOutput('(empty)');
193
194
await act(async () => {
195
start();
196
187
- expect(Scheduler).toFlushAndYield([
197
+ await waitForAll([
198
'Pending...',
199
'(empty)',
200
'Suspend! [Async]',
@@ -195,7 +205,7 @@ describe('ReactTransition', () => {
205
206
await resolveText('Async');
207
});
198
- expect(Scheduler).toHaveYielded(['Async']);
208
+ assertLog(['Async']);
209
expect(root).toMatchRenderedOutput('Async');
210
});
211
@@ -239,7 +249,7 @@ describe('ReactTransition', () => {
249
seedNextTextCache('A content');
250
root.render(<App />);
251
});
242
- expect(Scheduler).toHaveYielded(['A label', 'A content']);
252
+ assertLog(['A label', 'A content']);
253
expect(root).toMatchRenderedOutput(
254
<>
255
A label<div>A content</div>
@@ -250,7 +260,7 @@ describe('ReactTransition', () => {
260
await act(async () => {
261
update('B');
262
});
253
- expect(Scheduler).toHaveYielded([
263
+ assertLog([
264
// Commit pending state
265
'B label (loading...)',
266
'A content',
@@ -271,7 +281,7 @@ describe('ReactTransition', () => {
281
await act(async () => {
282
update('C');
283
});
274
- expect(Scheduler).toHaveYielded([
284
+ assertLog([
285
// Commit pending state
286
'C label (loading...)',
287
'A content',
@@ -292,7 +302,7 @@ describe('ReactTransition', () => {
302
await act(async () => {
303
resolveText('B content');
304
});
295
- expect(Scheduler).toHaveYielded([
305
+ assertLog([
306
// Attempt to render C, but it suspends
307
'C label',
308
'Suspend! [C content]',
@@ -308,7 +318,7 @@ describe('ReactTransition', () => {
318
await act(async () => {
319
resolveText('C content');
320
});
311
- expect(Scheduler).toHaveYielded(['C label', 'C content']);
321
+ assertLog(['C label', 'C content']);
322
expect(root).toMatchRenderedOutput(
323
<>
324
C label<div>C content</div>
@@ -364,7 +374,7 @@ describe('ReactTransition', () => {
374
seedNextTextCache('A content');
375
root.render(<App />);
376
});
367
- expect(Scheduler).toHaveYielded(['A label', 'A content']);
377
+ assertLog(['A label', 'A content']);
378
expect(root).toMatchRenderedOutput(
379
<>
380
A label<div>A content</div>
@@ -375,7 +385,7 @@ describe('ReactTransition', () => {
385
await act(async () => {
386
update('B');
387
});
378
- expect(Scheduler).toHaveYielded([
388
+ assertLog([
389
// Commit pending state
390
'B label (loading...)',
391
'A content',
@@ -396,7 +406,7 @@ describe('ReactTransition', () => {
406
await act(async () => {
407
update('C');
408
});
399
- expect(Scheduler).toHaveYielded([
409
+ assertLog([
410
// Commit pending state
411
'C label (loading...)',
412
'A content',
@@ -417,7 +427,7 @@ describe('ReactTransition', () => {
427
await act(async () => {
428
resolveText('B content');
429
});
420
- expect(Scheduler).toHaveYielded([
430
+ assertLog([
431
// Attempt to render C, but it suspends
432
'C label',
433
'Suspend! [C content]',
@@ -433,7 +443,7 @@ describe('ReactTransition', () => {
443
await act(async () => {
444
resolveText('C content');
445
});
436
- expect(Scheduler).toHaveYielded(['C label', 'C content']);
446
+ assertLog(['C label', 'C content']);
447
expect(root).toMatchRenderedOutput(
448
<>
449
C label<div>C content</div>
@@ -481,7 +491,7 @@ describe('ReactTransition', () => {
491
await act(async () => {
492
root.render(<App />);
493
});
484
- expect(Scheduler).toHaveYielded([]);
494
+ assertLog([]);
495
expect(root).toMatchRenderedOutput(null);
496
497
// Switch to A.
@@ -490,7 +500,7 @@ describe('ReactTransition', () => {
500
setShowA(true);
501
});
502
});
493
- expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Loading...']);
503
+ assertLog(['Suspend! [A]', 'Loading...']);
504
expect(root).toMatchRenderedOutput(null);
505
506
// Before A loads, switch to B. This should entangle A with B.
@@ -500,7 +510,7 @@ describe('ReactTransition', () => {
510
setShowB(true);
511
});
512
});
503
- expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...']);
513
+ assertLog(['Suspend! [B]', 'Loading...']);
514
expect(root).toMatchRenderedOutput(null);
515
516
// Before A or B loads, switch to C. This should entangle C with B, and
@@ -511,7 +521,7 @@ describe('ReactTransition', () => {
521
setShowC(true);
522
});
523
});
514
- expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
524
+ assertLog(['Suspend! [C]', 'Loading...']);
525
expect(root).toMatchRenderedOutput(null);
526
527
// Now the data starts resolving out of order.
@@ -523,7 +533,7 @@ describe('ReactTransition', () => {
533
resolveText('B');
534
});
535
});
526
- expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
536
+ assertLog(['Suspend! [C]', 'Loading...']);
537
expect(root).toMatchRenderedOutput(null);
538
539
// Now resolve A. Again, this will attempt to render C, since everything
@@ -533,7 +543,7 @@ describe('ReactTransition', () => {
543
resolveText('A');
544
});
545
});
536
- expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
546
+ assertLog(['Suspend! [C]', 'Loading...']);
547
expect(root).toMatchRenderedOutput(null);
548
549
// Finally, resolve C. This time we can finish.
@@ -542,7 +552,7 @@ describe('ReactTransition', () => {
552
resolveText('C');
553
});
554
});
545
- expect(Scheduler).toHaveYielded(['C']);
555
+ assertLog(['C']);
556
expect(root).toMatchRenderedOutput('C');
557
},
558
);
@@ -559,7 +569,7 @@ describe('ReactTransition', () => {
569
</>,
570
);
571
});
562
- expect(Scheduler).toHaveYielded(['Initial']);
572
+ assertLog(['Initial']);
573
expect(root).toMatchRenderedOutput('Initial');
574
575
await act(async () => {
@@ -577,7 +587,7 @@ describe('ReactTransition', () => {
587
});
588
589
// Partially render it.
580
- expect(Scheduler).toFlushAndYieldThrough([
590
+ await waitFor([
591
// Once we the update suspends, we know it's a refresh transition,
592
// because the Suspense boundary has already mounted.
593
'Suspend! [Async]',
@@ -598,7 +608,7 @@ describe('ReactTransition', () => {
608
609
// Because the first one is going to suspend regardless, we should
610
// immediately switch to rendering the new transition.
601
- expect(Scheduler).toHaveYielded(['Updated']);
611
+ assertLog(['Updated']);
612
expect(root).toMatchRenderedOutput('Updated');
613
});
614
@@ -643,12 +653,7 @@ describe('ReactTransition', () => {
653
654
await act(async () => {
655
root.render(<App />);
646
- expect(Scheduler).toFlushAndYield([
647
- 'A',
648
- 'shouldHideInParent: false',
649
- 'B',
650
- 'C',
651
- ]);
656
+ await waitForAll(['A', 'shouldHideInParent: false', 'B', 'C']);
657
expect(root).toMatchRenderedOutput('ABC');
658
659
// Schedule an update
@@ -660,14 +665,14 @@ describe('ReactTransition', () => {
665
// lane from the first one. At the time this was written, all transitions are worked on
666
// simultaneously, unless a transition was already in progress when a
667
// new one was scheduled. So, partially render the first transition.
663
- expect(Scheduler).toFlushAndYieldThrough(['A']);
668
+ await waitFor(['A']);
669
670
// Now schedule a second transition. We won't interrupt the first one.
671
React.startTransition(() => {
672
setShouldHideInParent(true);
673
});
674
// Continue rendering the first transition.
670
- expect(Scheduler).toFlushAndYieldThrough([
675
+ await waitFor([
676
'shouldHideInParent: false',
677
'Suspend! [Async]',
678
'Loading...',
@@ -683,16 +688,13 @@ describe('ReactTransition', () => {
688
// time we re-enter the work loop (we don't interrupt immediately, we
689
// just wait for the next time slice), we should throw out the
690
// suspended first transition and try the second one.
686
- expect(Scheduler).toFlushUntilNextPaint([
687
- 'shouldHideInParent: true',
688
- '(empty)',
689
- ]);
691
+ await waitForPaint(['shouldHideInParent: true', '(empty)']);
692
expect(root).toMatchRenderedOutput('A(empty)BC');
693
694
// Since the two transitions are not entangled, we then later go back
695
// and finish retry the first transition. Not really relevant to this
696
// test but I'll assert the result anyway.
695
- expect(Scheduler).toFlushAndYield([
697
+ await waitForAll([
698
'A',
699
'shouldHideInParent: true',
700
'(empty)',
@@ -732,7 +734,7 @@ describe('ReactTransition', () => {
734
await act(async () => {
735
root.render(<App shouldSuspend={false} step={0} />);
736
});
735
- expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0']);
737
+ assertLog(['A0', 'B0', 'C0']);
738
expect(root).toMatchRenderedOutput('A0B0C0');
739
740
await act(async () => {
@@ -741,14 +743,14 @@ describe('ReactTransition', () => {
743
root.render(<App shouldSuspend={true} step={1} />);
744
});
745
// Flush past the root, but stop before the async component.
744
- expect(Scheduler).toFlushAndYieldThrough(['A1']);
746
+ await waitFor(['A1']);
747
748
// Schedule another transition on the root, which already completed.
749
startTransition(() => {
750
root.render(<App shouldSuspend={false} step={2} />);
751
});
752
// We'll keep working on the first update.
751
- expect(Scheduler).toFlushAndYieldThrough([
753
+ await waitFor([
754
// Now the async component suspends
755
'Suspend! [Async]',
756
'Loading...',
@@ -762,7 +764,7 @@ describe('ReactTransition', () => {
764
// TODO: This should work even if React does not yield to the main
765
// thread. Should use same mechanism as selective hydration to interrupt
766
// the render before the end of the current slice of work.
765
- expect(Scheduler).toFlushAndYield(['A2', 'B2', 'C2']);
767
+ await waitForAll(['A2', 'B2', 'C2']);
768
769
expect(root).toMatchRenderedOutput('A2B2C2');
770
});
@@ -798,11 +800,7 @@ describe('ReactTransition', () => {
800
});
801
802
// Initial render.
801
- expect(Scheduler).toHaveYielded([
802
- 'Transition pri: 0',
803
- 'Normal pri: 0',
804
- 'Commit',
805
- ]);
803
+ assertLog(['Transition pri: 0', 'Normal pri: 0', 'Commit']);
804
expect(root).toMatchRenderedOutput('Transition pri: 0, Normal pri: 0');
805
806
await act(async () => {
@@ -810,7 +808,7 @@ describe('ReactTransition', () => {
808
updateNormalPri();
809
});
810
813
- expect(Scheduler).toHaveYielded([
811
+ assertLog([
812
// Normal update first.
813
'Transition pri: 0',
814
'Normal pri: 1',
@@ -854,14 +852,14 @@ describe('ReactTransition', () => {
852
});
853
854
// Initial render.
857
- expect(Scheduler).toHaveYielded(['(empty)', 'Normal pri: 0', 'Commit']);
855
+ assertLog(['(empty)', 'Normal pri: 0', 'Commit']);
856
expect(root).toMatchRenderedOutput('(empty), Normal pri: 0');
857
858
await act(async () => {
859
updateTransitionPri();
860
});
861
864
- expect(Scheduler).toHaveYielded([
862
+ assertLog([
863
// Suspend.
864
'Suspend! [Async]',
865
'Normal pri: 0',
@@ -874,7 +872,7 @@ describe('ReactTransition', () => {
872
updateNormalPri();
873
});
874
877
- expect(Scheduler).toHaveYielded([
875
+ assertLog([
876
// Normal pri update.
877
'(empty)',
878
'Normal pri: 1',
@@ -914,17 +912,13 @@ describe('ReactTransition', () => {
912
await act(async () => {
913
root.render(<App />);
914
});
917
- expect(Scheduler).toHaveYielded([
918
- 'Transition pri: 0',
919
- 'Normal pri: 0',
920
- 'Commit',
921
- ]);
915
+ assertLog(['Transition pri: 0', 'Normal pri: 0', 'Commit']);
916
expect(root).toMatchRenderedOutput('Transition pri: 0, Normal pri: 0');
917
918
await act(async () => {
919
updateTransitionPri();
920
927
- expect(Scheduler).toFlushAndYieldThrough([
921
+ await waitFor([
922
// Start transition update.
923
'Transition pri: 1',
924
]);
@@ -935,7 +929,7 @@ describe('ReactTransition', () => {
929
});
930
931
if (gate(flags => flags.enableUnifiedSyncLane)) {
938
- expect(Scheduler).toHaveYielded([
932
+ assertLog([
933
'Normal pri: 0',
934
'Commit',
935
@@ -945,7 +939,7 @@ describe('ReactTransition', () => {
939
'Commit',
940
]);
941
} else {
948
- expect(Scheduler).toHaveYielded([
942
+ assertLog([
943
// Finish transition update.
944
'Normal pri: 0',
945
'Commit',
packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js
+89
-86
@@ -12,6 +12,8 @@ let React;
12
let ReactNoop;
13
let Scheduler;
14
let act;
15
+let waitForAll;
16
+let assertLog;
17
18
let getCacheForType;
19
let useState;
@@ -43,6 +45,10 @@ describe('ReactInteractionTracing', () => {
45
46
act = require('jest-react').act;
47
48
+ const InternalTestUtils = require('internal-test-utils');
49
+ waitForAll = InternalTestUtils.waitForAll;
50
+ assertLog = InternalTestUtils.assertLog;
51
+
52
useState = React.useState;
53
startTransition = React.startTransition;
54
Suspense = React.Suspense;
@@ -233,7 +239,7 @@ describe('ReactInteractionTracing', () => {
239
ReactNoop.expire(1000);
240
await advanceTimers(1000);
241
236
- expect(Scheduler).toFlushAndYield(['Page One']);
242
+ await waitForAll(['Page One']);
243
244
await act(async () => {
245
startTransition(() => root.render(<App navigate={true} />));
@@ -242,12 +248,12 @@ describe('ReactInteractionTracing', () => {
248
await advanceTimers(1000);
249
250
// Doesn't call transition or marker code
245
- expect(Scheduler).toFlushAndYield(['Page Two']);
251
+ await waitForAll(['Page Two']);
252
253
startTransition(() => root.render(<App navigate={false} />), {
254
name: 'transition',
255
});
250
- expect(Scheduler).toFlushAndYield([
256
+ await waitForAll([
257
'Page One',
258
'onTransitionStart(transition, 2000)',
259
'onTransitionComplete(transition, 2000, 2000)',
@@ -299,7 +305,7 @@ describe('ReactInteractionTracing', () => {
305
ReactNoop.expire(1000);
306
await advanceTimers(1000);
307
302
- expect(Scheduler).toFlushAndYield(['Page One']);
308
+ await waitForAll(['Page One']);
309
310
await act(async () => {
311
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
@@ -307,7 +313,7 @@ describe('ReactInteractionTracing', () => {
313
ReactNoop.expire(1000);
314
await advanceTimers(1000);
315
310
- expect(Scheduler).toFlushAndYield([
316
+ await waitForAll([
317
'Page Two',
318
'onTransitionStart(page transition, 1000)',
319
'onTransitionComplete(page transition, 1000, 2000)',
@@ -358,7 +364,7 @@ describe('ReactInteractionTracing', () => {
364
ReactNoop.expire(1000);
365
await advanceTimers(1000);
366
361
- expect(Scheduler).toFlushAndYield(['Page One: hide']);
367
+ await waitForAll(['Page One: hide']);
368
369
await act(async () => {
370
startTransition(
@@ -372,7 +378,7 @@ describe('ReactInteractionTracing', () => {
378
ReactNoop.expire(1000);
379
await advanceTimers(1000);
380
375
- expect(Scheduler).toFlushAndYield([
381
+ await waitForAll([
382
'Page Two: show',
383
'onTransitionStart(page transition, 1000)',
384
'onTransitionComplete(page transition, 1000, 2000)',
@@ -431,7 +437,7 @@ describe('ReactInteractionTracing', () => {
437
ReactNoop.expire(1000);
438
await advanceTimers(1000);
439
434
- expect(Scheduler).toFlushAndYield(['Page One']);
440
+ await waitForAll(['Page One']);
441
});
442
443
await act(async () => {
@@ -440,7 +446,7 @@ describe('ReactInteractionTracing', () => {
446
ReactNoop.expire(1000);
447
await advanceTimers(1000);
448
443
- expect(Scheduler).toFlushAndYield([
449
+ await waitForAll([
450
'Suspend [Page Two]',
451
'Loading...',
452
'onTransitionStart(page transition, 1000)',
@@ -451,7 +457,7 @@ describe('ReactInteractionTracing', () => {
457
await advanceTimers(1000);
458
await resolveText('Page Two');
459
454
- expect(Scheduler).toFlushAndYield([
460
+ await waitForAll([
461
'Page Two',
462
'onTransitionProgress(page transition, 1000, 3000, [])',
463
'onTransitionComplete(page transition, 1000, 3000)',
@@ -526,13 +532,13 @@ describe('ReactInteractionTracing', () => {
532
ReactNoop.expire(1000);
533
await advanceTimers(1000);
534
529
- expect(Scheduler).toFlushAndYield(['Page One']);
535
+ await waitForAll(['Page One']);
536
});
537
538
await act(async () => {
539
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
540
535
- expect(Scheduler).toFlushAndYield([
541
+ await waitForAll([
542
'Suspend [Page Two]',
543
'Loading...',
544
'onTransitionStart(page transition, 1000)',
@@ -542,14 +548,14 @@ describe('ReactInteractionTracing', () => {
548
await resolveText('Page Two');
549
ReactNoop.expire(1000);
550
await advanceTimers(1000);
545
- expect(Scheduler).toFlushAndYield([
551
+ await waitForAll([
552
'Page Two',
553
'onTransitionProgress(page transition, 1000, 2000, [])',
554
'onTransitionComplete(page transition, 1000, 2000)',
555
]);
556
557
startTransition(() => showTextFn(), {name: 'text transition'});
552
- expect(Scheduler).toFlushAndYield([
558
+ await waitForAll([
559
'Suspend [Show Text]',
560
'Show Text Loading...',
561
'Page Two',
@@ -560,7 +566,7 @@ describe('ReactInteractionTracing', () => {
566
await resolveText('Show Text');
567
ReactNoop.expire(1000);
568
await advanceTimers(1000);
563
- expect(Scheduler).toFlushAndYield([
569
+ await waitForAll([
570
'Show Text',
571
'onTransitionProgress(text transition, 2000, 3000, [])',
572
'onTransitionComplete(text transition, 2000, 3000)',
@@ -633,7 +639,7 @@ describe('ReactInteractionTracing', () => {
639
ReactNoop.expire(1000);
640
await advanceTimers(1000);
641
636
- expect(Scheduler).toFlushAndYield(['Page One']);
642
+ await waitForAll(['Page One']);
643
});
644
645
await act(async () => {
@@ -641,7 +647,7 @@ describe('ReactInteractionTracing', () => {
647
ReactNoop.expire(1000);
648
await advanceTimers(1000);
649
644
- expect(Scheduler).toFlushAndYield([
650
+ await waitForAll([
651
'Suspend [Page Two]',
652
'Loading...',
653
'onTransitionStart(page transition, 1000)',
@@ -652,7 +658,7 @@ describe('ReactInteractionTracing', () => {
658
await act(async () => {
659
startTransition(() => showTextFn(), {name: 'show text'});
660
655
- expect(Scheduler).toFlushAndYield([
661
+ await waitForAll([
662
'Suspend [Show Text]',
663
'Show Text Loading...',
664
'Suspend [Page Two]',
@@ -667,7 +673,7 @@ describe('ReactInteractionTracing', () => {
673
ReactNoop.expire(1000);
674
await advanceTimers(1000);
675
670
- expect(Scheduler).toFlushAndYield([
676
+ await waitForAll([
677
'Page Two',
678
'onTransitionProgress(page transition, 1000, 3000, [])',
679
'onTransitionComplete(page transition, 1000, 3000)',
@@ -677,7 +683,7 @@ describe('ReactInteractionTracing', () => {
683
ReactNoop.expire(1000);
684
await advanceTimers(1000);
685
680
- expect(Scheduler).toFlushAndYield([
686
+ await waitForAll([
687
'Show Text',
688
'onTransitionProgress(show text, 2000, 4000, [])',
689
'onTransitionComplete(show text, 2000, 4000)',
@@ -750,7 +756,7 @@ describe('ReactInteractionTracing', () => {
756
ReactNoop.expire(1000);
757
await advanceTimers(1000);
758
753
- expect(Scheduler).toFlushAndYield(['Page One']);
759
+ await waitForAll(['Page One']);
760
});
761
762
await act(async () => {
@@ -758,7 +764,7 @@ describe('ReactInteractionTracing', () => {
764
ReactNoop.expire(1000);
765
await advanceTimers(1000);
766
761
- expect(Scheduler).toFlushAndYield([
767
+ await waitForAll([
768
'Suspend [Page Two]',
769
'Suspend [Show Text One]',
770
'Show Text One Loading...',
@@ -773,7 +779,7 @@ describe('ReactInteractionTracing', () => {
779
ReactNoop.expire(1000);
780
await advanceTimers(1000);
781
776
- expect(Scheduler).toFlushAndYield([
782
+ await waitForAll([
783
'Page Two',
784
'Suspend [Show Text One]',
785
'Show Text One Loading...',
@@ -786,7 +792,7 @@ describe('ReactInteractionTracing', () => {
792
ReactNoop.expire(1000);
793
await advanceTimers(1000);
794
789
- expect(Scheduler).toFlushAndYield([
795
+ await waitForAll([
796
'Show Text One',
797
'onTransitionProgress(page transition, 1000, 4000, [show text two])',
798
]);
@@ -795,7 +801,7 @@ describe('ReactInteractionTracing', () => {
801
ReactNoop.expire(1000);
802
await advanceTimers(1000);
803
798
- expect(Scheduler).toFlushAndYield([
804
+ await waitForAll([
805
'Show Text Two',
806
'onTransitionProgress(page transition, 1000, 5000, [])',
807
'onTransitionComplete(page transition, 1000, 5000)',
@@ -881,7 +887,7 @@ describe('ReactInteractionTracing', () => {
887
ReactNoop.expire(1000);
888
await advanceTimers(1000);
889
884
- expect(Scheduler).toFlushAndYield(['Page One']);
890
+ await waitForAll(['Page One']);
891
});
892
893
await act(async () => {
@@ -890,7 +896,7 @@ describe('ReactInteractionTracing', () => {
896
ReactNoop.expire(1000);
897
await advanceTimers(1000);
898
893
- expect(Scheduler).toFlushAndYield([
899
+ await waitForAll([
900
'Suspend [Page Two]',
901
'Suspend [Show Text One]',
902
'Show Text One Loading...',
@@ -906,7 +912,7 @@ describe('ReactInteractionTracing', () => {
912
resolveText('Page Two');
913
ReactNoop.expire(1000);
914
await advanceTimers(1000);
909
- expect(Scheduler).toFlushAndYield([
915
+ await waitForAll([
916
'Page Two',
917
'Suspend [Show Text One]',
918
'Show Text One Loading...',
@@ -920,7 +926,7 @@ describe('ReactInteractionTracing', () => {
926
ReactNoop.expire(1000);
927
await advanceTimers(1000);
928
923
- expect(Scheduler).toFlushAndYield([
929
+ await waitForAll([
930
'Page Two',
931
'Suspend [Show Text One]',
932
'Show Text One Loading...',
@@ -938,7 +944,7 @@ describe('ReactInteractionTracing', () => {
944
ReactNoop.expire(1000);
945
await advanceTimers(1000);
946
941
- expect(Scheduler).toFlushAndYield([
947
+ await waitForAll([
948
'Show Text',
949
'onTransitionProgress(navigate, 1000, 5000, [show text one])',
950
'onTransitionProgress(show text one, 1000, 5000, [show text one])',
@@ -948,7 +954,7 @@ describe('ReactInteractionTracing', () => {
954
resolveText('Show Text Two');
955
ReactNoop.expire(1000);
956
await advanceTimers(1000);
951
- expect(Scheduler).toFlushAndYield([
957
+ await waitForAll([
958
'Show Text Two',
959
'onTransitionProgress(show text two, 3000, 6000, [])',
960
'onTransitionComplete(show text two, 3000, 6000)',
@@ -959,7 +965,7 @@ describe('ReactInteractionTracing', () => {
965
ReactNoop.expire(1000);
966
await advanceTimers(1000);
967
962
- expect(Scheduler).toFlushAndYield([
968
+ await waitForAll([
969
'Show Text One',
970
'onTransitionProgress(navigate, 1000, 7000, [])',
971
'onTransitionProgress(show text one, 1000, 7000, [])',
@@ -1037,7 +1043,7 @@ describe('ReactInteractionTracing', () => {
1043
ReactNoop.expire(1000);
1044
await advanceTimers(1000);
1045
1040
- expect(Scheduler).toFlushAndYield(['Page One']);
1046
+ await waitForAll(['Page One']);
1047
1048
await act(async () => {
1049
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
@@ -1045,7 +1051,7 @@ describe('ReactInteractionTracing', () => {
1051
ReactNoop.expire(1000);
1052
await advanceTimers(1000);
1053
1048
- expect(Scheduler).toFlushAndYield([
1054
+ await waitForAll([
1055
'Page Two',
1056
'onTransitionStart(page transition, 1000)',
1057
'onMarkerComplete(page transition, marker two, 1000, 2000)',
@@ -1124,7 +1130,7 @@ describe('ReactInteractionTracing', () => {
1130
ReactNoop.expire(1000);
1131
await advanceTimers(1000);
1132
1127
- expect(Scheduler).toFlushAndYield(['Page One']);
1133
+ await waitForAll(['Page One']);
1134
});
1135
1136
await act(async () => {
@@ -1133,7 +1139,7 @@ describe('ReactInteractionTracing', () => {
1139
ReactNoop.expire(1000);
1140
await advanceTimers(1000);
1141
1136
- expect(Scheduler).toFlushAndYield([
1142
+ await waitForAll([
1143
'Suspend [Page Two]',
1144
'Suspend [Marker Text]',
1145
'Loading...',
@@ -1145,7 +1151,7 @@ describe('ReactInteractionTracing', () => {
1151
await advanceTimers(1000);
1152
await resolveText('Page Two');
1153
1148
- expect(Scheduler).toFlushAndYield([
1154
+ await waitForAll([
1155
'Page Two',
1156
'Suspend [Marker Text]',
1157
'Loading...',
@@ -1157,7 +1163,7 @@ describe('ReactInteractionTracing', () => {
1163
await advanceTimers(1000);
1164
await resolveText('Marker Text');
1165
1160
- expect(Scheduler).toFlushAndYield([
1166
+ await waitForAll([
1167
'Marker Text',
1168
'onMarkerProgress(page transition, async marker, 1000, 4000, [])',
1169
'onMarkerComplete(page transition, async marker, 1000, 4000)',
@@ -1244,7 +1250,7 @@ describe('ReactInteractionTracing', () => {
1250
ReactNoop.expire(1000);
1251
await advanceTimers(1000);
1252
1247
- expect(Scheduler).toFlushAndYield(['Page One']);
1253
+ await waitForAll(['Page One']);
1254
});
1255
1256
await act(async () => {
@@ -1253,7 +1259,7 @@ describe('ReactInteractionTracing', () => {
1259
ReactNoop.expire(1000);
1260
await advanceTimers(1000);
1261
1256
- expect(Scheduler).toFlushAndYield([
1262
+ await waitForAll([
1263
'Suspend [Outer Text]',
1264
'Suspend [Inner Text One]',
1265
'Inner One...',
@@ -1267,12 +1273,12 @@ describe('ReactInteractionTracing', () => {
1273
ReactNoop.expire(1000);
1274
await advanceTimers(1000);
1275
await resolveText('Inner Text Two');
1270
- expect(Scheduler).toFlushAndYield([]);
1276
+ await waitForAll([]);
1277
1278
ReactNoop.expire(1000);
1279
await advanceTimers(1000);
1280
await resolveText('Outer Text');
1275
- expect(Scheduler).toFlushAndYield([
1281
+ await waitForAll([
1282
'Outer Text',
1283
'Suspend [Inner Text One]',
1284
'Inner One...',
@@ -1284,7 +1290,7 @@ describe('ReactInteractionTracing', () => {
1290
ReactNoop.expire(1000);
1291
await advanceTimers(1000);
1292
await resolveText('Inner Text One');
1287
- expect(Scheduler).toFlushAndYield([
1293
+ await waitForAll([
1294
'Inner Text One',
1295
'onMarkerProgress(page transition, outer marker, 1000, 5000, [])',
1296
'onMarkerComplete(page transition, marker one, 1000, 5000)',
@@ -1367,7 +1373,7 @@ describe('ReactInteractionTracing', () => {
1373
root.render(<App navigate={false} markerName="marker one" />);
1374
ReactNoop.expire(1000);
1375
await advanceTimers(1000);
1370
- expect(Scheduler).toFlushAndYield(['Page One']);
1376
+ await waitForAll(['Page One']);
1377
1378
startTransition(
1379
() => root.render(<App navigate={true} markerName="marker one" />),
@@ -1378,7 +1384,7 @@ describe('ReactInteractionTracing', () => {
1384
ReactNoop.expire(1000);
1385
await advanceTimers(1000);
1386
1381
- expect(Scheduler).toFlushAndYield([
1387
+ await waitForAll([
1388
'Suspend [Page Two]',
1389
'Loading...',
1390
'onTransitionStart(transition one, 1000)',
@@ -1400,7 +1406,7 @@ describe('ReactInteractionTracing', () => {
1406
resolveText('Page Two');
1407
ReactNoop.expire(1000);
1408
await advanceTimers(1000);
1403
- expect(Scheduler).toFlushAndYield([
1409
+ await waitForAll([
1410
'Page Two',
1411
'onMarkerProgress(transition one, marker one, 1000, 4000, [])',
1412
'onTransitionProgress(transition one, 1000, 4000, [])',
@@ -1501,7 +1507,7 @@ describe('ReactInteractionTracing', () => {
1507
root.render(<App navigate={false} showMarker={true} />);
1508
ReactNoop.expire(1000);
1509
await advanceTimers(1000);
1504
- expect(Scheduler).toFlushAndYield(['Page One']);
1510
+ await waitForAll(['Page One']);
1511
1512
startTransition(
1513
() => root.render(<App navigate={true} showMarker={true} />),
@@ -1511,7 +1517,7 @@ describe('ReactInteractionTracing', () => {
1517
);
1518
ReactNoop.expire(1000);
1519
await advanceTimers(1000);
1514
- expect(Scheduler).toFlushAndYield([
1520
+ await waitForAll([
1521
'Suspend [Page Two]',
1522
'Loading...',
1523
'Suspend [Sibling Text]',
@@ -1526,7 +1532,7 @@ describe('ReactInteractionTracing', () => {
1532
1533
ReactNoop.expire(1000);
1534
await advanceTimers(1000);
1529
- expect(Scheduler).toFlushAndYield([
1535
+ await waitForAll([
1536
'Suspend [Page Two]',
1537
'Loading...',
1538
'Suspend [Sibling Text]',
@@ -1539,7 +1545,7 @@ describe('ReactInteractionTracing', () => {
1545
root.render(<App navigate={true} showMarker={true} />);
1546
ReactNoop.expire(1000);
1547
await advanceTimers(1000);
1542
- expect(Scheduler).toFlushAndYield([
1548
+ await waitForAll([
1549
'Suspend [Page Two]',
1550
'Loading...',
1551
'Suspend [Sibling Text]',
@@ -1550,12 +1556,12 @@ describe('ReactInteractionTracing', () => {
1556
resolveText('Page Two');
1557
ReactNoop.expire(1000);
1558
await advanceTimers(1000);
1553
- expect(Scheduler).toFlushAndYield(['Page Two']);
1559
+ await waitForAll(['Page Two']);
1560
1561
resolveText('Sibling Text');
1562
ReactNoop.expire(1000);
1563
await advanceTimers(1000);
1558
- expect(Scheduler).toFlushAndYield([
1564
+ await waitForAll([
1565
'Sibling Text',
1566
'onMarkerProgress(transition one, parent, 1000, 6000, [])',
1567
'onMarkerProgress(transition one, sibling, 1000, 6000, [])',
@@ -1652,7 +1658,7 @@ describe('ReactInteractionTracing', () => {
1658
root.render(<App navigate={false} deleteOne={false} />);
1659
ReactNoop.expire(1000);
1660
await advanceTimers(1000);
1655
- expect(Scheduler).toFlushAndYield(['Page One']);
1661
+ await waitForAll(['Page One']);
1662
1663
startTransition(
1664
() => root.render(<App navigate={true} deleteOne={false} />),
@@ -1662,7 +1668,7 @@ describe('ReactInteractionTracing', () => {
1668
);
1669
ReactNoop.expire(1000);
1670
await advanceTimers(1000);
1665
- expect(Scheduler).toFlushAndYield([
1671
+ await waitForAll([
1672
'Suspend [Page One]',
1673
'Loading One...',
1674
'Suspend [Page Two]',
@@ -1677,7 +1683,7 @@ describe('ReactInteractionTracing', () => {
1683
root.render(<App navigate={true} deleteOne={true} />);
1684
ReactNoop.expire(1000);
1685
await advanceTimers(1000);
1680
- expect(Scheduler).toFlushAndYield([
1686
+ await waitForAll([
1687
'Suspend [Page Two]',
1688
'Loading Two...',
1689
'onMarkerProgress(transition, parent, 1000, 3000, [suspense two])',
@@ -1688,7 +1694,7 @@ describe('ReactInteractionTracing', () => {
1694
await resolveText('Page Two');
1695
ReactNoop.expire(1000);
1696
await advanceTimers(1000);
1691
- expect(Scheduler).toFlushAndYield([
1697
+ await waitForAll([
1698
'Page Two',
1699
// Marker progress will still get called after incomplete but not marker complete
1700
'onMarkerProgress(transition, parent, 1000, 4000, [])',
@@ -1793,7 +1799,7 @@ describe('ReactInteractionTracing', () => {
1799
1800
ReactNoop.expire(1000);
1801
await advanceTimers(1000);
1796
- expect(Scheduler).toFlushAndYield(['Page One']);
1802
+ await waitForAll(['Page One']);
1803
1804
startTransition(
1805
() => root.render(<App navigate={true} deleteOne={false} />),
@@ -1803,7 +1809,7 @@ describe('ReactInteractionTracing', () => {
1809
);
1810
ReactNoop.expire(1000);
1811
await advanceTimers(1000);
1806
- expect(Scheduler).toFlushAndYield([
1812
+ await waitForAll([
1813
'Suspend [Page One]',
1814
'Suspend [Child]',
1815
'Loading Child...',
@@ -1820,7 +1826,7 @@ describe('ReactInteractionTracing', () => {
1826
await resolveText('Page One');
1827
ReactNoop.expire(1000);
1828
await advanceTimers(1000);
1823
- expect(Scheduler).toFlushAndYield([
1829
+ await waitForAll([
1830
'Page One',
1831
'Suspend [Child]',
1832
'Loading Child...',
@@ -1833,7 +1839,7 @@ describe('ReactInteractionTracing', () => {
1839
root.render(<App navigate={true} deleteOne={true} />);
1840
ReactNoop.expire(1000);
1841
await advanceTimers(1000);
1836
- expect(Scheduler).toFlushAndYield([
1842
+ await waitForAll([
1843
'Suspend [Page Two]',
1844
'Loading Two...',
1845
// "suspense one" has unsuspended so shouldn't be included
@@ -1848,7 +1854,7 @@ describe('ReactInteractionTracing', () => {
1854
await resolveText('Page Two');
1855
ReactNoop.expire(1000);
1856
await advanceTimers(1000);
1851
- expect(Scheduler).toFlushAndYield([
1857
+ await waitForAll([
1858
'Page Two',
1859
'onMarkerProgress(transition, parent, 1000, 5000, [])',
1860
'onMarkerProgress(transition, two, 1000, 5000, [])',
@@ -1933,7 +1939,7 @@ describe('ReactInteractionTracing', () => {
1939
ReactNoop.expire(1000);
1940
await advanceTimers(1000);
1941
1936
- expect(Scheduler).toFlushAndYield([
1942
+ await waitForAll([
1943
'Suspend [Child]',
1944
'onTransitionStart(transition, 0)',
1945
'onMarkerProgress(transition, parent, 0, 1000, [child])',
@@ -1945,23 +1951,20 @@ describe('ReactInteractionTracing', () => {
1951
await advanceTimers(1000);
1952
// This appended child isn't part of the transition so we
1953
// don't call any callback
1948
- expect(Scheduler).toFlushAndYield([
1949
- 'Suspend [Appended child]',
1950
- 'Suspend [Child]',
1951
- ]);
1954
+ await waitForAll(['Suspend [Appended child]', 'Suspend [Child]']);
1955
1956
// This deleted child isn't part of the transition so we
1957
// don't call any callbacks
1958
root.render(<App show={false} />);
1959
ReactNoop.expire(1000);
1960
await advanceTimers(1000);
1958
- expect(Scheduler).toFlushAndYield(['Suspend [Child]']);
1961
+ await waitForAll(['Suspend [Child]']);
1962
1963
await resolveText('Child');
1964
ReactNoop.expire(1000);
1965
await advanceTimers(1000);
1966
1964
- expect(Scheduler).toFlushAndYield([
1967
+ await waitForAll([
1968
'Child',
1969
'onMarkerProgress(transition, parent, 0, 4000, [])',
1970
'onMarkerComplete(transition, parent, 0, 4000)',
@@ -2056,7 +2059,7 @@ describe('ReactInteractionTracing', () => {
2059
await advanceTimers(1000);
2060
});
2061
2059
- expect(Scheduler).toHaveYielded([
2062
+ assertLog([
2063
'Suspend [Child]',
2064
'onTransitionStart(transition one, 0)',
2065
'onMarkerProgress(transition one, parent, 0, 1000, [child])',
@@ -2075,7 +2078,7 @@ describe('ReactInteractionTracing', () => {
2078
await advanceTimers(1000);
2079
});
2080
2078
- expect(Scheduler).toHaveYielded([
2081
+ assertLog([
2082
'Suspend [Appended child]',
2083
'Suspend [Child]',
2084
'onTransitionStart(transition two, 1000)',
@@ -2089,7 +2092,7 @@ describe('ReactInteractionTracing', () => {
2092
await advanceTimers(1000);
2093
});
2094
2092
- expect(Scheduler).toHaveYielded([
2095
+ assertLog([
2096
'Suspend [Child]',
2097
'onMarkerProgress(transition two, appended child, 1000, 3000, [])',
2098
'onMarkerIncomplete(transition two, appended child, 1000, [{endTime: 3000, name: appended child, type: suspense}])',
@@ -2101,7 +2104,7 @@ describe('ReactInteractionTracing', () => {
2104
await advanceTimers(1000);
2105
});
2106
2104
- expect(Scheduler).toHaveYielded([
2107
+ assertLog([
2108
'Child',
2109
'onMarkerProgress(transition one, parent, 0, 4000, [])',
2110
'onMarkerComplete(transition one, parent, 0, 4000)',
@@ -2161,7 +2164,7 @@ describe('ReactInteractionTracing', () => {
2164
);
2165
ReactNoop.expire(1000);
2166
await advanceTimers(1000);
2164
- expect(Scheduler).toFlushAndYield([
2167
+ await waitForAll([
2168
'one',
2169
'onTransitionStart(transition one, 0)',
2170
'onMarkerComplete(transition one, one, 0, 1000)',
@@ -2175,10 +2178,10 @@ describe('ReactInteractionTracing', () => {
2178
);
2179
ReactNoop.expire(1000);
2180
await advanceTimers(1000);
2178
- expect(() => {
2181
+ await expect(async () => {
2182
// onMarkerComplete shouldn't be called for transitions with
2183
// new keys
2181
- expect(Scheduler).toFlushAndYield([
2184
+ await waitForAll([
2185
'two',
2186
'onTransitionStart(transition two, 1000)',
2187
'onTransitionComplete(transition two, 1000, 2000)',
@@ -2195,7 +2198,7 @@ describe('ReactInteractionTracing', () => {
2198
ReactNoop.expire(1000);
2199
await advanceTimers(1000);
2200
// This should not warn and onMarkerComplete should be called
2198
- expect(Scheduler).toFlushAndYield([
2201
+ await waitForAll([
2202
'three',
2203
'onTransitionStart(transition three, 2000)',
2204
'onMarkerComplete(transition three, three, 2000, 3000)',
@@ -2247,7 +2250,7 @@ describe('ReactInteractionTracing', () => {
2250
ReactNoop.expire(1000);
2251
advanceTimers(1000);
2252
});
2250
- expect(Scheduler).toHaveYielded([
2253
+ assertLog([
2254
'Suspend [Text]',
2255
'Loading...',
2256
'Suspend [Hidden Text]',
@@ -2260,7 +2263,7 @@ describe('ReactInteractionTracing', () => {
2263
ReactNoop.expire(1000);
2264
advanceTimers(1000);
2265
});
2263
- expect(Scheduler).toHaveYielded([
2266
+ assertLog([
2267
'Text',
2268
'onMarkerComplete(transition, marker, 0, 2000)',
2269
'onTransitionComplete(transition, 0, 2000)',
@@ -2271,7 +2274,7 @@ describe('ReactInteractionTracing', () => {
2274
ReactNoop.expire(1000);
2275
advanceTimers(1000);
2276
});
2274
- expect(Scheduler).toHaveYielded(['Hidden Text']);
2277
+ assertLog(['Hidden Text']);
2278
});
2279
2280
// @gate enableTransitionTracing
@@ -2317,7 +2320,7 @@ describe('ReactInteractionTracing', () => {
2320
await advanceTimers(1000);
2321
});
2322
2320
- expect(Scheduler).toHaveYielded([
2323
+ assertLog([
2324
'Suspend [Page Two]',
2325
'Loading...',
2326
'onTransitionStart(page transition, 0)',
@@ -2329,7 +2332,7 @@ describe('ReactInteractionTracing', () => {
2332
await advanceTimers(1000);
2333
});
2334
2332
- expect(Scheduler).toHaveYielded([
2335
+ assertLog([
2336
'Page Two',
2337
'onTransitionProgress(page transition, 0, 2000, [])',
2338
'onTransitionComplete(page transition, 0, 2000)',
@@ -2387,7 +2390,7 @@ describe('ReactInteractionTracing', () => {
2390
advanceTimers(1000);
2391
});
2392
2390
- expect(Scheduler).toHaveYielded([
2393
+ assertLog([
2394
'Suspend [Text]',
2395
'Loading...',
2396
'Suspend [Text Two]',
@@ -2404,7 +2407,7 @@ describe('ReactInteractionTracing', () => {
2407
ReactNoop.expire(1000);
2408
advanceTimers(1000);
2409
});
2407
- expect(Scheduler).toHaveYielded([
2410
+ assertLog([
2411
'Text Two',
2412
'onTransitionProgress(transition, 0, 2000, [])',
2413
'onTransitionComplete(transition, 0, 2000)',
@@ -2465,7 +2468,7 @@ describe('ReactInteractionTracing', () => {
2468
advanceTimers(1000);
2469
});
2470
2468
- expect(Scheduler).toHaveYielded([
2471
+ assertLog([
2472
'Suspend [Text one]',
2473
'Loading one...',
2474
'Suspend [Text two]',
@@ -2482,7 +2485,7 @@ describe('ReactInteractionTracing', () => {
2485
advanceTimers(1000);
2486
});
2487
2485
- expect(Scheduler).toHaveYielded([
2488
+ assertLog([
2489
'Text one',
2490
'onTransitionProgress(transition one, 0, 2000, []) /root one/',
2491
'onTransitionComplete(transition one, 0, 2000) /root one/',
@@ -2494,7 +2497,7 @@ describe('ReactInteractionTracing', () => {
2497
advanceTimers(1000);
2498
});
2499
2497
- expect(Scheduler).toHaveYielded([
2500
+ assertLog([
2501
'Text two',
2502
'onTransitionProgress(transition two, 0, 3000, []) /root two/',
2503
'onTransitionComplete(transition two, 0, 3000) /root two/',
packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js
+16
-8
@@ -6,6 +6,9 @@ let startTransition;
6
let useState;
7
let useEffect;
8
let act;
9
+let waitFor;
10
+let waitForPaint;
11
+let assertLog;
12
13
describe('ReactUpdatePriority', () => {
14
beforeEach(() => {
@@ -20,6 +23,11 @@ describe('ReactUpdatePriority', () => {
23
startTransition = React.startTransition;
24
useState = React.useState;
25
useEffect = React.useEffect;
26
+
27
+ const InternalTestUtils = require('internal-test-utils');
28
+ waitFor = InternalTestUtils.waitFor;
29
+ waitForPaint = InternalTestUtils.waitForPaint;
30
+ assertLog = InternalTestUtils.assertLog;
31
});
32
33
function Text({text}) {
@@ -43,9 +51,9 @@ describe('ReactUpdatePriority', () => {
51
root.render(<App />);
52
});
53
// Should not have flushed the effect update yet
46
- expect(Scheduler).toHaveYielded([1]);
54
+ assertLog([1]);
55
});
48
- expect(Scheduler).toHaveYielded([2]);
56
+ assertLog([2]);
57
});
58
59
test('setState inside passive effect triggered by idle update should have idle priority', async () => {
@@ -68,13 +76,13 @@ describe('ReactUpdatePriority', () => {
76
root.render(<App />);
77
});
78
// Should not have flushed the effect update yet
71
- expect(Scheduler).toFlushUntilNextPaint(['Idle: 1, Default: 1']);
79
+ await waitForPaint(['Idle: 1, Default: 1']);
80
81
// Schedule another update at default priority
82
setDefaultState(2);
83
84
// The default update flushes first, because
77
- expect(Scheduler).toFlushUntilNextPaint([
85
+ await waitForPaint([
86
// Idle update is scheduled
87
'Idle update',
88
@@ -83,7 +91,7 @@ describe('ReactUpdatePriority', () => {
91
]);
92
});
93
// Now the idle update has flushed
86
- expect(Scheduler).toHaveYielded(['Idle: 2, Default: 2']);
94
+ assertLog(['Idle: 2, Default: 2']);
95
});
96
97
test('continuous updates should interrupt transitions', async () => {
@@ -111,19 +119,19 @@ describe('ReactUpdatePriority', () => {
119
await act(async () => {
120
root.render(<App />);
121
});
114
- expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']);
122
+ assertLog(['A1', 'B1', 'C1']);
123
expect(root).toMatchRenderedOutput('A1B1C1');
124
125
await act(async () => {
126
startTransition(() => {
127
setCounter(2);
128
});
121
- expect(Scheduler).toFlushAndYieldThrough(['A2']);
129
+ await waitFor(['A2']);
130
ReactNoop.unstable_runWithPriority(ContinuousEventPriority, () => {
131
setIsHidden(true);
132
});
133
});
126
- expect(Scheduler).toHaveYielded([
134
+ assertLog([
135
// Because the hide update has continuous priority, it should interrupt the
136
// in-progress transition
137
'(hidden)',
packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
+25
-20
@@ -19,6 +19,9 @@ let allSchedulerTags;
19
let allSchedulerTypes;
20
let onCommitRootShouldYield;
21
let act;
22
+let waitFor;
23
+let waitForAll;
24
+let assertLog;
25
26
describe('updaters', () => {
27
beforeEach(() => {
@@ -91,6 +94,11 @@ describe('updaters', () => {
94
Scheduler = require('scheduler');
95
96
act = require('jest-react').act;
97
+
98
+ const InternalTestUtils = require('internal-test-utils');
99
+ waitFor = InternalTestUtils.waitFor;
100
+ waitForAll = InternalTestUtils.waitForAll;
101
+ assertLog = InternalTestUtils.assertLog;
102
});
103
104
it('should report the (host) root as the scheduler for root-level render', async () => {
@@ -210,10 +218,7 @@ describe('updaters', () => {
218
const root = ReactDOMClient.createRoot(document.createElement('div'));
219
await act(async () => {
220
root.render(<Parent />);
213
- expect(Scheduler).toFlushAndYieldThrough([
214
- 'CascadingChild 0',
215
- 'onCommitRoot',
216
- ]);
221
+ await waitFor(['CascadingChild 0', 'onCommitRoot']);
222
});
223
expect(triggerActiveCascade).not.toBeNull();
224
expect(triggerPassiveCascade).not.toBeNull();
@@ -221,7 +226,7 @@ describe('updaters', () => {
226
227
await act(async () => {
228
triggerActiveCascade();
224
- expect(Scheduler).toFlushAndYieldThrough([
229
+ await waitFor([
230
'CascadingChild 0',
231
'onCommitRoot',
232
'CascadingChild 1',
@@ -236,7 +241,7 @@ describe('updaters', () => {
241
242
await act(async () => {
243
triggerPassiveCascade();
239
- expect(Scheduler).toFlushAndYieldThrough([
244
+ await waitFor([
245
'CascadingChild 1',
246
'onCommitRoot',
247
'CascadingChild 2',
@@ -252,7 +257,7 @@ describe('updaters', () => {
257
]);
258
259
// Verify no outstanding flushes
255
- Scheduler.unstable_flushAll();
260
+ await waitForAll([]);
261
});
262
263
it('should cover suspense pings', async () => {
@@ -291,7 +296,7 @@ describe('updaters', () => {
296
297
await act(async () => {
298
ReactDOM.render(<Parent />, document.createElement('div'));
294
- expect(Scheduler).toHaveYielded(['onCommitRoot']);
299
+ assertLog(['onCommitRoot']);
300
});
301
expect(setShouldSuspend).not.toBeNull();
302
expect(allSchedulerTypes).toEqual([[null]]);
@@ -299,7 +304,7 @@ describe('updaters', () => {
304
await act(async () => {
305
setShouldSuspend(true);
306
});
302
- expect(Scheduler).toHaveYielded(['onCommitRoot']);
307
+ assertLog(['onCommitRoot']);
308
expect(allSchedulerTypes).toEqual([[null], [Suspender]]);
309
310
expect(resolver).not.toBeNull();
@@ -307,11 +312,11 @@ describe('updaters', () => {
312
resolver('abc');
313
return promise;
314
});
310
- expect(Scheduler).toHaveYielded(['onCommitRoot']);
315
+ assertLog(['onCommitRoot']);
316
expect(allSchedulerTypes).toEqual([[null], [Suspender], [Suspender]]);
317
318
// Verify no outstanding flushes
314
- Scheduler.unstable_flushAll();
319
+ await waitForAll([]);
320
});
321
322
it('should cover error handling', async () => {
@@ -354,7 +359,7 @@ describe('updaters', () => {
359
await act(async () => {
360
root.render(<Parent shouldError={false} />);
361
});
357
- expect(Scheduler).toHaveYielded(['initial', 'onCommitRoot']);
362
+ assertLog(['initial', 'onCommitRoot']);
363
expect(triggerError).not.toBeNull();
364
365
allSchedulerTypes.splice(0);
@@ -363,11 +368,11 @@ describe('updaters', () => {
368
await act(async () => {
369
triggerError();
370
});
366
- expect(Scheduler).toHaveYielded(['onCommitRoot', 'error', 'onCommitRoot']);
371
+ assertLog(['onCommitRoot', 'error', 'onCommitRoot']);
372
expect(allSchedulerTypes).toEqual([[Parent], [ErrorBoundary]]);
373
374
// Verify no outstanding flushes
370
- Scheduler.unstable_flushAll();
375
+ await waitForAll([]);
376
});
377
378
it('should distinguish between updaters in the case of interleaved work', async () => {
@@ -409,7 +414,7 @@ describe('updaters', () => {
414
);
415
416
// Render everything initially.
412
- expect(Scheduler).toFlushAndYield([
417
+ await waitForAll([
418
'SyncPriorityUpdater 0',
419
'Yield HighPriority 0',
420
'LowPriorityUpdater 0',
@@ -421,14 +426,14 @@ describe('updaters', () => {
426
expect(allSchedulerTags).toEqual([[HostRoot]]);
427
428
// Render a partial update, but don't finish.
424
- act(() => {
429
+ await act(async () => {
430
triggerLowPriorityUpdate();
426
- expect(Scheduler).toFlushAndYieldThrough(['LowPriorityUpdater 1']);
431
+ await waitFor(['LowPriorityUpdater 1']);
432
expect(allSchedulerTags).toEqual([[HostRoot]]);
433
434
// Interrupt with higher priority work.
435
ReactDOM.flushSync(triggerSyncPriorityUpdate);
431
- expect(Scheduler).toHaveYielded([
436
+ assertLog([
437
'SyncPriorityUpdater 1',
438
'Yield HighPriority 1',
439
'onCommitRoot',
@@ -437,7 +442,7 @@ describe('updaters', () => {
442
443
// Finish the initial partial update
444
triggerLowPriorityUpdate();
440
- expect(Scheduler).toFlushAndYield([
445
+ await waitForAll([
446
'LowPriorityUpdater 2',
447
'Yield LowPriority 2',
448
'onCommitRoot',
@@ -455,6 +460,6 @@ describe('updaters', () => {
460
]);
461
462
// Verify no outstanding flushes
458
- Scheduler.unstable_flushAll();
463
+ await waitForAll([]);
464
});
465
});
packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js
+38
-64
@@ -13,6 +13,7 @@ let React;
13
let ReactTestRenderer;
14
let Scheduler;
15
let act;
16
+let assertLog;
17
18
describe('StrictEffectsMode', () => {
19
beforeEach(() => {
@@ -21,6 +22,9 @@ describe('StrictEffectsMode', () => {
22
ReactTestRenderer = require('react-test-renderer');
23
Scheduler = require('scheduler');
24
act = require('jest-react').act;
25
+
26
+ const InternalTestUtils = require('internal-test-utils');
27
+ assertLog = InternalTestUtils.assertLog;
28
});
29
30
function supportsDoubleInvokeEffects() {
@@ -51,10 +55,7 @@ describe('StrictEffectsMode', () => {
55
ReactTestRenderer.create(<App text={'mount'} />);
56
});
57
54
- expect(Scheduler).toHaveYielded([
55
- 'useLayoutEffect mount',
56
- 'useEffect mount',
57
- ]);
58
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
59
});
60
61
it('double invoking for effects works properly', () => {
@@ -80,7 +81,7 @@ describe('StrictEffectsMode', () => {
81
});
82
83
if (supportsDoubleInvokeEffects()) {
83
- expect(Scheduler).toHaveYielded([
84
+ assertLog([
85
'useLayoutEffect mount',
86
'useEffect mount',
87
'useLayoutEffect unmount',
@@ -89,17 +90,14 @@ describe('StrictEffectsMode', () => {
90
'useEffect mount',
91
]);
92
} else {
92
- expect(Scheduler).toHaveYielded([
93
- 'useLayoutEffect mount',
94
- 'useEffect mount',
95
- ]);
93
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
94
}
95
96
act(() => {
97
renderer.update(<App text={'update'} />);
98
});
99
102
- expect(Scheduler).toHaveYielded([
100
+ assertLog([
101
'useLayoutEffect unmount',
102
'useLayoutEffect mount',
103
'useEffect unmount',
@@ -110,10 +108,7 @@ describe('StrictEffectsMode', () => {
108
renderer.unmount();
109
});
110
113
- expect(Scheduler).toHaveYielded([
114
- 'useLayoutEffect unmount',
115
- 'useEffect unmount',
116
- ]);
111
+ assertLog(['useLayoutEffect unmount', 'useEffect unmount']);
112
});
113
114
it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
@@ -139,7 +134,7 @@ describe('StrictEffectsMode', () => {
134
});
135
136
if (supportsDoubleInvokeEffects()) {
142
- expect(Scheduler).toHaveYielded([
137
+ assertLog([
138
'useEffect One mount',
139
'useEffect Two mount',
140
'useEffect One unmount',
@@ -148,17 +143,14 @@ describe('StrictEffectsMode', () => {
143
'useEffect Two mount',
144
]);
145
} else {
151
- expect(Scheduler).toHaveYielded([
152
- 'useEffect One mount',
153
- 'useEffect Two mount',
154
- ]);
146
+ assertLog(['useEffect One mount', 'useEffect Two mount']);
147
}
148
149
act(() => {
150
renderer.update(<App text={'update'} />);
151
});
152
161
- expect(Scheduler).toHaveYielded([
153
+ assertLog([
154
'useEffect One unmount',
155
'useEffect Two unmount',
156
'useEffect One mount',
@@ -169,10 +161,7 @@ describe('StrictEffectsMode', () => {
161
renderer.unmount(null);
162
});
163
172
- expect(Scheduler).toHaveYielded([
173
- 'useEffect One unmount',
174
- 'useEffect Two unmount',
175
- ]);
164
+ assertLog(['useEffect One unmount', 'useEffect Two unmount']);
165
});
166
167
it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
@@ -200,7 +189,7 @@ describe('StrictEffectsMode', () => {
189
});
190
191
if (supportsDoubleInvokeEffects()) {
203
- expect(Scheduler).toHaveYielded([
192
+ assertLog([
193
'useLayoutEffect One mount',
194
'useLayoutEffect Two mount',
195
'useLayoutEffect One unmount',
@@ -209,17 +198,14 @@ describe('StrictEffectsMode', () => {
198
'useLayoutEffect Two mount',
199
]);
200
} else {
212
- expect(Scheduler).toHaveYielded([
213
- 'useLayoutEffect One mount',
214
- 'useLayoutEffect Two mount',
215
- ]);
201
+ assertLog(['useLayoutEffect One mount', 'useLayoutEffect Two mount']);
202
}
203
204
act(() => {
205
renderer.update(<App text={'update'} />);
206
});
207
222
- expect(Scheduler).toHaveYielded([
208
+ assertLog([
209
'useLayoutEffect One unmount',
210
'useLayoutEffect Two unmount',
211
'useLayoutEffect One mount',
@@ -230,10 +216,7 @@ describe('StrictEffectsMode', () => {
216
renderer.unmount();
217
});
218
233
- expect(Scheduler).toHaveYielded([
234
- 'useLayoutEffect One unmount',
235
- 'useLayoutEffect Two unmount',
236
- ]);
219
+ assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']);
220
});
221
222
it('useEffect and useLayoutEffect is called twice when there is no unmount', () => {
@@ -257,33 +240,27 @@ describe('StrictEffectsMode', () => {
240
});
241
242
if (supportsDoubleInvokeEffects()) {
260
- expect(Scheduler).toHaveYielded([
243
+ assertLog([
244
'useLayoutEffect mount',
245
'useEffect mount',
246
'useLayoutEffect mount',
247
'useEffect mount',
248
]);
249
} else {
267
- expect(Scheduler).toHaveYielded([
268
- 'useLayoutEffect mount',
269
- 'useEffect mount',
270
- ]);
250
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
251
}
252
253
act(() => {
254
renderer.update(<App text={'update'} />);
255
});
256
277
- expect(Scheduler).toHaveYielded([
278
- 'useLayoutEffect mount',
279
- 'useEffect mount',
280
- ]);
257
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
258
259
act(() => {
260
renderer.unmount();
261
});
262
286
- expect(Scheduler).toHaveYielded([]);
263
+ assertLog([]);
264
});
265
266
it('passes the right context to class component lifecycles', () => {
@@ -315,13 +292,13 @@ describe('StrictEffectsMode', () => {
292
});
293
294
if (supportsDoubleInvokeEffects()) {
318
- expect(Scheduler).toHaveYielded([
295
+ assertLog([
296
'componentDidMount',
297
'componentWillUnmount',
298
'componentDidMount',
299
]);
300
} else {
324
- expect(Scheduler).toHaveYielded(['componentDidMount']);
301
+ assertLog(['componentDidMount']);
302
}
303
});
304
@@ -352,26 +329,26 @@ describe('StrictEffectsMode', () => {
329
});
330
331
if (supportsDoubleInvokeEffects()) {
355
- expect(Scheduler).toHaveYielded([
332
+ assertLog([
333
'componentDidMount',
334
'componentWillUnmount',
335
'componentDidMount',
336
]);
337
} else {
361
- expect(Scheduler).toHaveYielded(['componentDidMount']);
338
+ assertLog(['componentDidMount']);
339
}
340
341
act(() => {
342
renderer.update(<App text={'update'} />);
343
});
344
368
- expect(Scheduler).toHaveYielded(['componentDidUpdate']);
345
+ assertLog(['componentDidUpdate']);
346
347
act(() => {
348
renderer.unmount();
349
});
350
374
- expect(Scheduler).toHaveYielded(['componentWillUnmount']);
351
+ assertLog(['componentWillUnmount']);
352
});
353
354
it('should not double invoke class lifecycles in legacy mode', () => {
@@ -397,7 +374,7 @@ describe('StrictEffectsMode', () => {
374
ReactTestRenderer.create(<App text={'mount'} />);
375
});
376
400
- expect(Scheduler).toHaveYielded(['componentDidMount']);
377
+ assertLog(['componentDidMount']);
378
});
379
380
it('double flushing passive effects only results in one double invoke', () => {
@@ -427,7 +404,7 @@ describe('StrictEffectsMode', () => {
404
});
405
406
if (supportsDoubleInvokeEffects()) {
430
- expect(Scheduler).toHaveYielded([
407
+ assertLog([
408
'mount',
409
'useLayoutEffect mount',
410
'useEffect mount',
@@ -442,7 +419,7 @@ describe('StrictEffectsMode', () => {
419
'useEffect mount',
420
]);
421
} else {
445
- expect(Scheduler).toHaveYielded([
422
+ assertLog([
423
'mount',
424
'useLayoutEffect mount',
425
'useEffect mount',
@@ -492,7 +469,7 @@ describe('StrictEffectsMode', () => {
469
});
470
471
if (supportsDoubleInvokeEffects()) {
495
- expect(Scheduler).toHaveYielded([
472
+ assertLog([
473
'App useLayoutEffect mount',
474
'App useEffect mount',
475
'App useLayoutEffect unmount',
@@ -501,10 +478,7 @@ describe('StrictEffectsMode', () => {
478
'App useEffect mount',
479
]);
480
} else {
504
- expect(Scheduler).toHaveYielded([
505
- 'App useLayoutEffect mount',
506
- 'App useEffect mount',
507
- ]);
481
+ assertLog(['App useLayoutEffect mount', 'App useEffect mount']);
482
}
483
484
act(() => {
@@ -512,7 +486,7 @@ describe('StrictEffectsMode', () => {
486
});
487
488
if (supportsDoubleInvokeEffects()) {
515
- expect(Scheduler).toHaveYielded([
489
+ assertLog([
490
'App useLayoutEffect unmount',
491
'Child useLayoutEffect mount',
492
'App useLayoutEffect mount',
@@ -525,7 +499,7 @@ describe('StrictEffectsMode', () => {
499
'Child useEffect mount',
500
]);
501
} else {
528
- expect(Scheduler).toHaveYielded([
502
+ assertLog([
503
'App useLayoutEffect unmount',
504
'Child useLayoutEffect mount',
505
'App useLayoutEffect mount',
@@ -580,7 +554,7 @@ describe('StrictEffectsMode', () => {
554
});
555
556
if (supportsDoubleInvokeEffects()) {
583
- expect(Scheduler).toHaveYielded([
557
+ assertLog([
558
'componentDidMount',
559
'useLayoutEffect mount',
560
'useEffect mount',
@@ -592,7 +566,7 @@ describe('StrictEffectsMode', () => {
566
'useEffect mount',
567
]);
568
} else {
595
- expect(Scheduler).toHaveYielded([
569
+ assertLog([
570
'componentDidMount',
571
'useLayoutEffect mount',
572
'useEffect mount',
@@ -603,7 +577,7 @@ describe('StrictEffectsMode', () => {
577
renderer.update(<App text={'mount'} />);
578
});
579
606
- expect(Scheduler).toHaveYielded([
580
+ assertLog([
581
'useLayoutEffect unmount',
582
'useLayoutEffect mount',
583
'useEffect unmount',
@@ -614,7 +588,7 @@ describe('StrictEffectsMode', () => {
588
renderer.unmount();
589
});
590
617
- expect(Scheduler).toHaveYielded([
591
+ assertLog([
592
'componentWillUnmount',
593
'useLayoutEffect unmount',
594
'useEffect unmount',
packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js
+46
-51
@@ -13,6 +13,10 @@ let React;
13
let ReactNoop;
14
let Scheduler;
15
let act;
16
+let assertLog;
17
+let waitFor;
18
+let waitForAll;
19
+let waitForPaint;
20
21
describe('StrictEffectsMode defaults', () => {
22
beforeEach(() => {
@@ -23,6 +27,12 @@ describe('StrictEffectsMode defaults', () => {
27
Scheduler = require('scheduler');
28
act = require('jest-react').act;
29
30
+ const InternalTestUtils = require('internal-test-utils');
31
+ waitFor = InternalTestUtils.waitFor;
32
+ waitForAll = InternalTestUtils.waitForAll;
33
+ waitForPaint = InternalTestUtils.waitForPaint;
34
+ assertLog = InternalTestUtils.assertLog;
35
+
36
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
37
ReactFeatureFlags.createRootStrictEffectsByDefault = __DEV__;
38
});
@@ -46,10 +56,7 @@ describe('StrictEffectsMode defaults', () => {
56
ReactNoop.renderLegacySyncRoot(<App text={'mount'} />);
57
});
58
49
- expect(Scheduler).toHaveYielded([
50
- 'useLayoutEffect mount',
51
- 'useEffect mount',
52
- ]);
59
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
60
});
61
62
it('should not double invoke class lifecycles in legacy mode', () => {
@@ -75,11 +82,11 @@ describe('StrictEffectsMode defaults', () => {
82
ReactNoop.renderLegacySyncRoot(<App text={'mount'} />);
83
});
84
78
- expect(Scheduler).toHaveYielded(['componentDidMount']);
85
+ assertLog(['componentDidMount']);
86
});
87
88
if (__DEV__) {
82
- it('should flush double-invoked effects within the same frame as layout effects if there are no passive effects', () => {
89
+ it('should flush double-invoked effects within the same frame as layout effects if there are no passive effects', async () => {
90
function ComponentWithEffects({label}) {
91
React.useLayoutEffect(() => {
92
Scheduler.unstable_yieldValue(`useLayoutEffect mount "${label}"`);
@@ -90,21 +97,21 @@ describe('StrictEffectsMode defaults', () => {
97
return label;
98
}
99
93
- act(() => {
100
+ await act(async () => {
101
ReactNoop.render(
102
<>
103
<ComponentWithEffects label={'one'} />
104
</>,
105
);
106
100
- expect(Scheduler).toFlushUntilNextPaint([
107
+ await waitForPaint([
108
'useLayoutEffect mount "one"',
109
'useLayoutEffect unmount "one"',
110
'useLayoutEffect mount "one"',
111
]);
112
});
113
107
- act(() => {
114
+ await act(async () => {
115
ReactNoop.render(
116
<>
117
<ComponentWithEffects label={'one'} />
@@ -112,8 +119,8 @@ describe('StrictEffectsMode defaults', () => {
119
</>,
120
);
121
115
- expect(Scheduler).toHaveYielded([]);
116
- expect(Scheduler).toFlushUntilNextPaint([
122
+ assertLog([]);
123
+ await waitForPaint([
124
// Cleanup and re-run "one" (and "two") since there is no dependencies array.
125
'useLayoutEffect unmount "one"',
126
'useLayoutEffect mount "one"',
@@ -128,7 +135,7 @@ describe('StrictEffectsMode defaults', () => {
135
136
// This test also verifies that double-invoked effects flush synchronously
137
// within the same frame as passive effects.
131
- it('should double invoke effects only for newly mounted components', () => {
138
+ it('should double invoke effects only for newly mounted components', async () => {
139
function ComponentWithEffects({label}) {
140
React.useEffect(() => {
141
Scheduler.unstable_yieldValue(`useEffect mount "${label}"`);
@@ -145,14 +152,14 @@ describe('StrictEffectsMode defaults', () => {
152
return label;
153
}
154
148
- act(() => {
155
+ await act(async () => {
156
ReactNoop.render(
157
<>
158
<ComponentWithEffects label={'one'} />
159
</>,
160
);
161
155
- expect(Scheduler).toFlushAndYield([
162
+ await waitForAll([
163
'useLayoutEffect mount "one"',
164
'useEffect mount "one"',
165
'useLayoutEffect unmount "one"',
@@ -162,7 +169,7 @@ describe('StrictEffectsMode defaults', () => {
169
]);
170
});
171
165
- act(() => {
172
+ await act(async () => {
173
ReactNoop.render(
174
<>
175
<ComponentWithEffects label={'one'} />
@@ -170,13 +177,13 @@ describe('StrictEffectsMode defaults', () => {
177
</>,
178
);
179
173
- expect(Scheduler).toFlushAndYieldThrough([
180
+ await waitFor([
181
// Cleanup and re-run "one" (and "two") since there is no dependencies array.
182
'useLayoutEffect unmount "one"',
183
'useLayoutEffect mount "one"',
184
'useLayoutEffect mount "two"',
185
]);
179
- expect(Scheduler).toFlushAndYield([
186
+ await waitForAll([
187
'useEffect unmount "one"',
188
'useEffect mount "one"',
189
'useEffect mount "two"',
@@ -208,7 +215,7 @@ describe('StrictEffectsMode defaults', () => {
215
ReactNoop.render(<App text={'mount'} />);
216
});
217
211
- expect(Scheduler).toHaveYielded([
218
+ assertLog([
219
'useLayoutEffect mount',
220
'useEffect mount',
221
'useLayoutEffect unmount',
@@ -221,7 +228,7 @@ describe('StrictEffectsMode defaults', () => {
228
ReactNoop.render(<App text={'update'} />);
229
});
230
224
- expect(Scheduler).toHaveYielded([
231
+ assertLog([
232
'useLayoutEffect unmount',
233
'useLayoutEffect mount',
234
'useEffect unmount',
@@ -232,10 +239,7 @@ describe('StrictEffectsMode defaults', () => {
239
ReactNoop.render(null);
240
});
241
235
- expect(Scheduler).toHaveYielded([
236
- 'useLayoutEffect unmount',
237
- 'useEffect unmount',
238
- ]);
242
+ assertLog(['useLayoutEffect unmount', 'useEffect unmount']);
243
});
244
245
it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
@@ -257,7 +261,7 @@ describe('StrictEffectsMode defaults', () => {
261
ReactNoop.render(<App text={'mount'} />);
262
});
263
260
- expect(Scheduler).toHaveYielded([
264
+ assertLog([
265
'useEffect One mount',
266
'useEffect Two mount',
267
'useEffect One unmount',
@@ -270,7 +274,7 @@ describe('StrictEffectsMode defaults', () => {
274
ReactNoop.render(<App text={'update'} />);
275
});
276
273
- expect(Scheduler).toHaveYielded([
277
+ assertLog([
278
'useEffect One unmount',
279
'useEffect Two unmount',
280
'useEffect One mount',
@@ -281,10 +285,7 @@ describe('StrictEffectsMode defaults', () => {
285
ReactNoop.render(null);
286
});
287
284
- expect(Scheduler).toHaveYielded([
285
- 'useEffect One unmount',
286
- 'useEffect Two unmount',
287
- ]);
288
+ assertLog(['useEffect One unmount', 'useEffect Two unmount']);
289
});
290
291
it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
@@ -308,7 +309,7 @@ describe('StrictEffectsMode defaults', () => {
309
ReactNoop.render(<App text={'mount'} />);
310
});
311
311
- expect(Scheduler).toHaveYielded([
312
+ assertLog([
313
'useLayoutEffect One mount',
314
'useLayoutEffect Two mount',
315
'useLayoutEffect One unmount',
@@ -321,7 +322,7 @@ describe('StrictEffectsMode defaults', () => {
322
ReactNoop.render(<App text={'update'} />);
323
});
324
324
- expect(Scheduler).toHaveYielded([
325
+ assertLog([
326
'useLayoutEffect One unmount',
327
'useLayoutEffect Two unmount',
328
'useLayoutEffect One mount',
@@ -332,10 +333,7 @@ describe('StrictEffectsMode defaults', () => {
333
ReactNoop.render(null);
334
});
335
335
- expect(Scheduler).toHaveYielded([
336
- 'useLayoutEffect One unmount',
337
- 'useLayoutEffect Two unmount',
338
- ]);
336
+ assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']);
337
});
338
339
it('useEffect and useLayoutEffect is called twice when there is no unmount', () => {
@@ -355,7 +353,7 @@ describe('StrictEffectsMode defaults', () => {
353
ReactNoop.render(<App text={'mount'} />);
354
});
355
358
- expect(Scheduler).toHaveYielded([
356
+ assertLog([
357
'useLayoutEffect mount',
358
'useEffect mount',
359
'useLayoutEffect mount',
@@ -366,16 +364,13 @@ describe('StrictEffectsMode defaults', () => {
364
ReactNoop.render(<App text={'update'} />);
365
});
366
369
- expect(Scheduler).toHaveYielded([
370
- 'useLayoutEffect mount',
371
- 'useEffect mount',
372
- ]);
367
+ assertLog(['useLayoutEffect mount', 'useEffect mount']);
368
369
act(() => {
370
ReactNoop.render(null);
371
});
372
378
- expect(Scheduler).toHaveYielded([]);
373
+ assertLog([]);
374
});
375
376
//@gate useModernStrictMode
@@ -430,7 +425,7 @@ describe('StrictEffectsMode defaults', () => {
425
ReactNoop.render(<App />);
426
});
427
433
- expect(Scheduler).toHaveYielded([
428
+ assertLog([
429
'componentDidMount',
430
'componentWillUnmount',
431
'componentDidMount',
@@ -460,7 +455,7 @@ describe('StrictEffectsMode defaults', () => {
455
ReactNoop.render(<App text={'mount'} />);
456
});
457
463
- expect(Scheduler).toHaveYielded([
458
+ assertLog([
459
'componentDidMount',
460
'componentWillUnmount',
461
'componentDidMount',
@@ -470,13 +465,13 @@ describe('StrictEffectsMode defaults', () => {
465
ReactNoop.render(<App text={'update'} />);
466
});
467
473
- expect(Scheduler).toHaveYielded(['componentDidUpdate']);
468
+ assertLog(['componentDidUpdate']);
469
470
act(() => {
471
ReactNoop.render(null);
472
});
473
479
- expect(Scheduler).toHaveYielded(['componentWillUnmount']);
474
+ assertLog(['componentWillUnmount']);
475
});
476
477
it('double flushing passive effects only results in one double invoke', () => {
@@ -503,7 +498,7 @@ describe('StrictEffectsMode defaults', () => {
498
ReactNoop.render(<App text={'mount'} />);
499
});
500
506
- expect(Scheduler).toHaveYielded([
501
+ assertLog([
502
'mount',
503
'useLayoutEffect mount',
504
'useEffect mount',
@@ -555,7 +550,7 @@ describe('StrictEffectsMode defaults', () => {
550
ReactNoop.render(<App />);
551
});
552
558
- expect(Scheduler).toHaveYielded([
553
+ assertLog([
554
'App useLayoutEffect mount',
555
'App useEffect mount',
556
'App useLayoutEffect unmount',
@@ -568,7 +563,7 @@ describe('StrictEffectsMode defaults', () => {
563
_setShowChild(true);
564
});
565
571
- expect(Scheduler).toHaveYielded([
566
+ assertLog([
567
'App useLayoutEffect unmount',
568
'Child useLayoutEffect mount',
569
'App useLayoutEffect mount',
@@ -622,7 +617,7 @@ describe('StrictEffectsMode defaults', () => {
617
ReactNoop.render(<App text={'mount'} />);
618
});
619
625
- expect(Scheduler).toHaveYielded([
620
+ assertLog([
621
'componentDidMount',
622
'useLayoutEffect mount',
623
'useEffect mount',
@@ -638,7 +633,7 @@ describe('StrictEffectsMode defaults', () => {
633
ReactNoop.render(<App text={'mount'} />);
634
});
635
641
- expect(Scheduler).toHaveYielded([
636
+ assertLog([
637
'useLayoutEffect unmount',
638
'useLayoutEffect mount',
639
'useEffect unmount',
@@ -649,7 +644,7 @@ describe('StrictEffectsMode defaults', () => {
644
ReactNoop.render(null);
645
});
646
652
- expect(Scheduler).toHaveYielded([
647
+ assertLog([
648
'componentWillUnmount',
649
'useLayoutEffect unmount',
650
'useEffect unmount',
packages/react-reconciler/src/__tests__/useEffectEvent-test.js
+60
-63
@@ -26,6 +26,8 @@ describe('useEffectEvent', () => {
26
let useEffect;
27
let useLayoutEffect;
28
let useMemo;
29
+ let waitForAll;
30
+ let assertLog;
31
32
beforeEach(() => {
33
React = require('react');
@@ -40,6 +42,10 @@ describe('useEffectEvent', () => {
42
useEffect = React.useEffect;
43
useLayoutEffect = React.useLayoutEffect;
44
useMemo = React.useMemo;
45
+
46
+ const InternalTestUtils = require('internal-test-utils');
47
+ waitForAll = InternalTestUtils.waitForAll;
48
+ assertLog = InternalTestUtils.assertLog;
49
});
50
51
function Text(props) {
@@ -48,7 +54,7 @@ describe('useEffectEvent', () => {
54
}
55
56
// @gate enableUseEffectEventHook
51
- it('memoizes basic case correctly', () => {
57
+ it('memoizes basic case correctly', async () => {
58
class IncrementButton extends React.PureComponent {
59
increment = () => {
60
this.props.onClick();
@@ -72,7 +78,7 @@ describe('useEffectEvent', () => {
78
79
const button = React.createRef(null);
80
ReactNoop.render(<Counter incrementBy={1} />);
75
- expect(Scheduler).toFlushAndYield(['Increment', 'Count: 0']);
81
+ await waitForAll(['Increment', 'Count: 0']);
82
expect(ReactNoop).toMatchRenderedOutput(
83
<>
84
<span prop="Increment" />
@@ -81,7 +87,7 @@ describe('useEffectEvent', () => {
87
);
88
89
act(button.current.increment);
84
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 1']);
90
+ assertLog(['Increment', 'Count: 1']);
91
expect(ReactNoop).toMatchRenderedOutput(
92
<>
93
<span prop="Increment" />
@@ -90,7 +96,7 @@ describe('useEffectEvent', () => {
96
);
97
98
act(button.current.increment);
93
- expect(Scheduler).toHaveYielded([
99
+ assertLog([
100
'Increment',
101
// Event should use the updated callback function closed over the new value.
102
'Count: 2',
@@ -104,7 +110,7 @@ describe('useEffectEvent', () => {
110
111
// Increase the increment prop amount
112
ReactNoop.render(<Counter incrementBy={10} />);
107
- expect(Scheduler).toFlushAndYield(['Increment', 'Count: 2']);
113
+ await waitForAll(['Increment', 'Count: 2']);
114
expect(ReactNoop).toMatchRenderedOutput(
115
<>
116
<span prop="Increment" />
@@ -114,7 +120,7 @@ describe('useEffectEvent', () => {
120
121
// Event uses the new prop
122
act(button.current.increment);
117
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 12']);
123
+ assertLog(['Increment', 'Count: 12']);
124
expect(ReactNoop).toMatchRenderedOutput(
125
<>
126
<span prop="Increment" />
@@ -124,7 +130,7 @@ describe('useEffectEvent', () => {
130
});
131
132
// @gate enableUseEffectEventHook
127
- it('can be defined more than once', () => {
133
+ it('can be defined more than once', async () => {
134
class IncrementButton extends React.PureComponent {
135
increment = () => {
136
this.props.onClick();
@@ -158,7 +164,7 @@ describe('useEffectEvent', () => {
164
165
const button = React.createRef(null);
166
ReactNoop.render(<Counter incrementBy={5} />);
161
- expect(Scheduler).toFlushAndYield(['Increment', 'Count: 0']);
167
+ await waitForAll(['Increment', 'Count: 0']);
168
expect(ReactNoop).toMatchRenderedOutput(
169
<>
170
<span prop="Increment" />
@@ -167,7 +173,7 @@ describe('useEffectEvent', () => {
173
);
174
175
act(button.current.increment);
170
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 5']);
176
+ assertLog(['Increment', 'Count: 5']);
177
expect(ReactNoop).toMatchRenderedOutput(
178
<>
179
<span prop="Increment" />
@@ -176,7 +182,7 @@ describe('useEffectEvent', () => {
182
);
183
184
act(button.current.multiply);
179
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 25']);
185
+ assertLog(['Increment', 'Count: 25']);
186
expect(ReactNoop).toMatchRenderedOutput(
187
<>
188
<span prop="Increment" />
@@ -186,7 +192,7 @@ describe('useEffectEvent', () => {
192
});
193
194
// @gate enableUseEffectEventHook
189
- it('does not preserve `this` in event functions', () => {
195
+ it('does not preserve `this` in event functions', async () => {
196
class GreetButton extends React.PureComponent {
197
greet = () => {
198
this.props.onClick();
@@ -217,7 +223,7 @@ describe('useEffectEvent', () => {
223
224
const button = React.createRef(null);
225
ReactNoop.render(<Greeter hello={'hej'} />);
220
- expect(Scheduler).toFlushAndYield(['Say hej', 'Greeting: Seb says hej']);
226
+ await waitForAll(['Say hej', 'Greeting: Seb says hej']);
227
expect(ReactNoop).toMatchRenderedOutput(
228
<>
229
<span prop="Say hej" />
@@ -226,10 +232,7 @@ describe('useEffectEvent', () => {
232
);
233
234
act(button.current.greet);
229
- expect(Scheduler).toHaveYielded([
230
- 'Say hej',
231
- 'Greeting: undefined says hej',
232
- ]);
235
+ assertLog(['Say hej', 'Greeting: undefined says hej']);
236
expect(ReactNoop).toMatchRenderedOutput(
237
<>
238
<span prop="Say hej" />
@@ -272,11 +275,11 @@ describe('useEffectEvent', () => {
275
276
// If something throws, we try one more time synchronously in case the error was
277
// caused by a data race. See recoverFromConcurrentError
275
- expect(Scheduler).toHaveYielded(['Count: 0', 'Count: 0']);
278
+ assertLog(['Count: 0', 'Count: 0']);
279
});
280
281
// @gate enableUseEffectEventHook
279
- it("useLayoutEffect shouldn't re-fire when event handlers change", () => {
282
+ it("useLayoutEffect shouldn't re-fire when event handlers change", async () => {
283
class IncrementButton extends React.PureComponent {
284
increment = () => {
285
this.props.onClick();
@@ -307,8 +310,8 @@ describe('useEffectEvent', () => {
310
311
const button = React.createRef(null);
312
ReactNoop.render(<Counter incrementBy={1} />);
310
- expect(Scheduler).toHaveYielded([]);
311
- expect(Scheduler).toFlushAndYield([
313
+ assertLog([]);
314
+ await waitForAll([
315
'Increment',
316
'Count: 0',
317
'Effect: by 2',
@@ -323,7 +326,7 @@ describe('useEffectEvent', () => {
326
);
327
328
act(button.current.increment);
326
- expect(Scheduler).toHaveYielded([
329
+ assertLog([
330
'Increment',
331
// Effect should not re-run because the dependency hasn't changed.
332
'Count: 3',
@@ -336,7 +339,7 @@ describe('useEffectEvent', () => {
339
);
340
341
act(button.current.increment);
339
- expect(Scheduler).toHaveYielded([
342
+ assertLog([
343
'Increment',
344
// Event should use the updated callback function closed over the new value.
345
'Count: 4',
@@ -350,7 +353,7 @@ describe('useEffectEvent', () => {
353
354
// Increase the increment prop amount
355
ReactNoop.render(<Counter incrementBy={10} />);
353
- expect(Scheduler).toFlushAndYield([
356
+ await waitForAll([
357
'Increment',
358
'Count: 4',
359
'Effect: by 20',
@@ -366,7 +369,7 @@ describe('useEffectEvent', () => {
369
370
// Event uses the new prop
371
act(button.current.increment);
369
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
372
+ assertLog(['Increment', 'Count: 34']);
373
expect(ReactNoop).toMatchRenderedOutput(
374
<>
375
<span prop="Increment" />
@@ -376,7 +379,7 @@ describe('useEffectEvent', () => {
379
});
380
381
// @gate enableUseEffectEventHook
379
- it("useEffect shouldn't re-fire when event handlers change", () => {
382
+ it("useEffect shouldn't re-fire when event handlers change", async () => {
383
class IncrementButton extends React.PureComponent {
384
increment = () => {
385
this.props.onClick();
@@ -407,7 +410,7 @@ describe('useEffectEvent', () => {
410
411
const button = React.createRef(null);
412
ReactNoop.render(<Counter incrementBy={1} />);
410
- expect(Scheduler).toFlushAndYield([
413
+ await waitForAll([
414
'Increment',
415
'Count: 0',
416
'Effect: by 2',
@@ -422,7 +425,7 @@ describe('useEffectEvent', () => {
425
);
426
427
act(button.current.increment);
425
- expect(Scheduler).toHaveYielded([
428
+ assertLog([
429
'Increment',
430
// Effect should not re-run because the dependency hasn't changed.
431
'Count: 3',
@@ -435,7 +438,7 @@ describe('useEffectEvent', () => {
438
);
439
440
act(button.current.increment);
438
- expect(Scheduler).toHaveYielded([
441
+ assertLog([
442
'Increment',
443
// Event should use the updated callback function closed over the new value.
444
'Count: 4',
@@ -449,7 +452,7 @@ describe('useEffectEvent', () => {
452
453
// Increase the increment prop amount
454
ReactNoop.render(<Counter incrementBy={10} />);
452
- expect(Scheduler).toFlushAndYield([
455
+ await waitForAll([
456
'Increment',
457
'Count: 4',
458
'Effect: by 20',
@@ -465,7 +468,7 @@ describe('useEffectEvent', () => {
468
469
// Event uses the new prop
470
act(button.current.increment);
468
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
471
+ assertLog(['Increment', 'Count: 34']);
472
expect(ReactNoop).toMatchRenderedOutput(
473
<>
474
<span prop="Increment" />
@@ -475,7 +478,7 @@ describe('useEffectEvent', () => {
478
});
479
480
// @gate enableUseEffectEventHook
478
- it('is stable in a custom hook', () => {
481
+ it('is stable in a custom hook', async () => {
482
class IncrementButton extends React.PureComponent {
483
increment = () => {
484
this.props.onClick();
@@ -512,7 +515,7 @@ describe('useEffectEvent', () => {
515
516
const button = React.createRef(null);
517
ReactNoop.render(<Counter incrementBy={1} />);
515
- expect(Scheduler).toFlushAndYield([
518
+ await waitForAll([
519
'Increment',
520
'Count: 0',
521
'Effect: by 2',
@@ -527,7 +530,7 @@ describe('useEffectEvent', () => {
530
);
531
532
act(button.current.increment);
530
- expect(Scheduler).toHaveYielded([
533
+ assertLog([
534
'Increment',
535
// Effect should not re-run because the dependency hasn't changed.
536
'Count: 3',
@@ -540,7 +543,7 @@ describe('useEffectEvent', () => {
543
);
544
545
act(button.current.increment);
543
- expect(Scheduler).toHaveYielded([
546
+ assertLog([
547
'Increment',
548
// Event should use the updated callback function closed over the new value.
549
'Count: 4',
@@ -554,7 +557,7 @@ describe('useEffectEvent', () => {
557
558
// Increase the increment prop amount
559
ReactNoop.render(<Counter incrementBy={10} />);
557
- expect(Scheduler).toFlushAndYield([
560
+ await waitForAll([
561
'Increment',
562
'Count: 4',
563
'Effect: by 20',
@@ -570,7 +573,7 @@ describe('useEffectEvent', () => {
573
574
// Event uses the new prop
575
act(button.current.increment);
573
- expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
576
+ assertLog(['Increment', 'Count: 34']);
577
expect(ReactNoop).toMatchRenderedOutput(
578
<>
579
<span prop="Increment" />
@@ -580,7 +583,7 @@ describe('useEffectEvent', () => {
583
});
584
585
// @gate enableUseEffectEventHook
583
- it('is mutated before all other effects', () => {
586
+ it('is mutated before all other effects', async () => {
587
function Counter({value}) {
588
useInsertionEffect(() => {
589
Scheduler.unstable_yieldValue('Effect value: ' + value);
@@ -597,14 +600,14 @@ describe('useEffectEvent', () => {
600
}
601
602
ReactNoop.render(<Counter value={1} />);
600
- expect(Scheduler).toFlushAndYield(['Effect value: 1', 'Event value: 1']);
603
+ await waitForAll(['Effect value: 1', 'Event value: 1']);
604
605
act(() => ReactNoop.render(<Counter value={2} />));
603
- expect(Scheduler).toHaveYielded(['Effect value: 2', 'Event value: 2']);
606
+ assertLog(['Effect value: 2', 'Event value: 2']);
607
});
608
609
// @gate enableUseEffectEventHook
607
- it("doesn't provide a stable identity", () => {
610
+ it("doesn't provide a stable identity", async () => {
611
function Counter({shouldRender, value}) {
612
const onClick = useEffectEvent(() => {
613
Scheduler.unstable_yieldValue(
@@ -627,16 +630,16 @@ describe('useEffectEvent', () => {
630
}
631
632
ReactNoop.render(<Counter shouldRender={true} value={0} />);
630
- expect(Scheduler).toFlushAndYield([
633
+ await waitForAll([
634
'onClick, shouldRender=true, value=0',
635
'onClick, shouldRender=true, value=0',
636
]);
637
638
ReactNoop.render(<Counter shouldRender={true} value={1} />);
636
- expect(Scheduler).toFlushAndYield(['onClick, shouldRender=true, value=1']);
639
+ await waitForAll(['onClick, shouldRender=true, value=1']);
640
641
ReactNoop.render(<Counter shouldRender={false} value={2} />);
639
- expect(Scheduler).toFlushAndYield([
642
+ await waitForAll([
643
'onClick, shouldRender=false, value=2',
644
'onClick, shouldRender=false, value=2',
645
]);
@@ -676,7 +679,7 @@ describe('useEffectEvent', () => {
679
await act(async () => {
680
root.render(<App value={1} />);
681
});
679
- expect(Scheduler).toHaveYielded(['Commit new event handler']);
682
+ assertLog(['Commit new event handler']);
683
expect(root).toMatchRenderedOutput('Latest rendered value 1');
684
expect(committedEventHandler()).toBe('Value seen by useEffectEvent: 1');
685
@@ -686,14 +689,14 @@ describe('useEffectEvent', () => {
689
});
690
// No new event handler should be committed, because it was omitted from
691
// the dependency array.
689
- expect(Scheduler).toHaveYielded([]);
692
+ assertLog([]);
693
// But the event handler should still be able to see the latest value.
694
expect(root).toMatchRenderedOutput('Latest rendered value 2');
695
expect(committedEventHandler()).toBe('Value seen by useEffectEvent: 2');
696
});
697
698
// @gate enableUseEffectEventHook
696
- it('integration: implements docs chat room example', () => {
699
+ it('integration: implements docs chat room example', async () => {
700
function createConnection() {
701
let connectedCallback;
702
let timeout;
@@ -738,47 +741,47 @@ describe('useEffectEvent', () => {
741
}
742
743
act(() => ReactNoop.render(<ChatRoom roomId="general" theme="light" />));
741
- expect(Scheduler).toHaveYielded(['Welcome to the general room!']);
744
+ assertLog(['Welcome to the general room!']);
745
expect(ReactNoop).toMatchRenderedOutput(
746
<span prop="Welcome to the general room!" />,
747
);
748
749
jest.advanceTimersByTime(100);
750
Scheduler.unstable_advanceTime(100);
748
- expect(Scheduler).toHaveYielded(['Connected! theme: light']);
751
+ assertLog(['Connected! theme: light']);
752
753
// change roomId only
754
act(() => ReactNoop.render(<ChatRoom roomId="music" theme="light" />));
752
- expect(Scheduler).toHaveYielded(['Welcome to the music room!']);
755
+ assertLog(['Welcome to the music room!']);
756
expect(ReactNoop).toMatchRenderedOutput(
757
<span prop="Welcome to the music room!" />,
758
);
759
jest.advanceTimersByTime(100);
760
Scheduler.unstable_advanceTime(100);
761
// should trigger a reconnect
759
- expect(Scheduler).toHaveYielded(['Connected! theme: light']);
762
+ assertLog(['Connected! theme: light']);
763
764
// change theme only
765
act(() => ReactNoop.render(<ChatRoom roomId="music" theme="dark" />));
763
- expect(Scheduler).toHaveYielded(['Welcome to the music room!']);
766
+ assertLog(['Welcome to the music room!']);
767
expect(ReactNoop).toMatchRenderedOutput(
768
<span prop="Welcome to the music room!" />,
769
);
770
jest.advanceTimersByTime(100);
771
Scheduler.unstable_advanceTime(100);
772
// should not trigger a reconnect
770
- expect(Scheduler).toFlushWithoutYielding();
773
+ await waitForAll([]);
774
775
// change roomId only
776
act(() => ReactNoop.render(<ChatRoom roomId="travel" theme="dark" />));
774
- expect(Scheduler).toHaveYielded(['Welcome to the travel room!']);
777
+ assertLog(['Welcome to the travel room!']);
778
expect(ReactNoop).toMatchRenderedOutput(
779
<span prop="Welcome to the travel room!" />,
780
);
781
jest.advanceTimersByTime(100);
782
Scheduler.unstable_advanceTime(100);
783
// should trigger a reconnect
781
- expect(Scheduler).toHaveYielded(['Connected! theme: dark']);
784
+ assertLog(['Connected! theme: dark']);
785
});
786
787
// @gate enableUseEffectEventHook
@@ -837,12 +840,9 @@ describe('useEffectEvent', () => {
840
</AppShell>,
841
),
842
);
840
- expect(Scheduler).toHaveYielded([
841
- 'Add to cart',
842
- 'url: /shop/1, numberOfItems: 0',
843
- ]);
843
+ assertLog(['Add to cart', 'url: /shop/1, numberOfItems: 0']);
844
act(button.current.addToCart);
845
- expect(Scheduler).toHaveYielded(['Add to cart']);
845
+ assertLog(['Add to cart']);
846
847
act(() =>
848
ReactNoop.render(
@@ -851,9 +851,6 @@ describe('useEffectEvent', () => {
851
</AppShell>,
852
),
853
);
854
- expect(Scheduler).toHaveYielded([
855
- 'Add to cart',
856
- 'url: /shop/2, numberOfItems: 1',
857
- ]);
854
+ assertLog(['Add to cart', 'url: /shop/2, numberOfItems: 1']);
855
});
856
});