@samitouri / QOS-React-2 / commits / 3cb5afb82e

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 });