@samitouri / QOS-React-2 / commits / ce8a72fd4e

Codemod tests to waitFor pattern (2/?) (#26296)

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 3, 2023 at 17:01 UTC ce8a72fd4e7a6de12e57dc9db59b4b6ce92daa3b
14 files changed +449 -388
packages/react-cache/src/__tests__/ReactCacheOld-test.internal.js
+34 -42
@@ -18,6 +18,8 @@ let Scheduler;
18 let Suspense;
19 let TextResource;
20 let textResourceShouldFail;
21 +let waitForAll;
22 +let assertLog;
23
24 describe('ReactCache', () => {
25 beforeEach(() => {
@@ -33,6 +35,10 @@ describe('ReactCache', () => {
35 ReactTestRenderer = require('react-test-renderer');
36 Scheduler = require('scheduler');
37
38 + const InternalTestUtils = require('internal-test-utils');
39 + waitForAll = InternalTestUtils.waitForAll;
40 + assertLog = InternalTestUtils.assertLog;
41 +
42 TextResource = createResource(
43 ([text, ms = 0]) => {
44 let listeners = null;
@@ -105,7 +111,7 @@ describe('ReactCache', () => {
111 }
112 }
113
108 - it('throws a promise if the requested value is not in the cache', () => {
114 + it('throws a promise if the requested value is not in the cache', async () => {
115 function App() {
116 return (
117 <Suspense fallback={<Text text="Loading..." />}>
@@ -118,11 +124,11 @@ describe('ReactCache', () => {
124 unstable_isConcurrent: true,
125 });
126
121 - expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
127 + await waitForAll(['Suspend! [Hi]', 'Loading...']);
128
129 jest.advanceTimersByTime(100);
124 - expect(Scheduler).toHaveYielded(['Promise resolved [Hi]']);
125 - expect(Scheduler).toFlushAndYield(['Hi']);
130 + assertLog(['Promise resolved [Hi]']);
131 + await waitForAll(['Hi']);
132 });
133
134 it('throws an error on the subsequent read if the promise is rejected', async () => {
@@ -138,22 +144,22 @@ describe('ReactCache', () => {
144 unstable_isConcurrent: true,
145 });
146
141 - expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
147 + await waitForAll(['Suspend! [Hi]', 'Loading...']);
148
149 textResourceShouldFail = true;
150 jest.advanceTimersByTime(100);
145 - expect(Scheduler).toHaveYielded(['Promise rejected [Hi]']);
151 + assertLog(['Promise rejected [Hi]']);
152
153 expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
148 - expect(Scheduler).toHaveYielded(['Error! [Hi]', 'Error! [Hi]']);
154 + assertLog(['Error! [Hi]', 'Error! [Hi]']);
155
156 // Should throw again on a subsequent read
157 root.update(<App />);
158 expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
153 - expect(Scheduler).toHaveYielded(['Error! [Hi]', 'Error! [Hi]']);
159 + assertLog(['Error! [Hi]', 'Error! [Hi]']);
160 });
161
156 - it('warns if non-primitive key is passed to a resource without a hash function', () => {
162 + it('warns if non-primitive key is passed to a resource without a hash function', async () => {
163 const BadTextResource = createResource(([text, ms = 0]) => {
164 return new Promise((resolve, reject) =>
165 setTimeout(() => {
@@ -177,8 +183,8 @@ describe('ReactCache', () => {
183 );
184
185 if (__DEV__) {
180 - expect(() => {
181 - expect(Scheduler).toFlushAndYield(['App', 'Loading...']);
186 + expect(async () => {
187 + await waitForAll(['App', 'Loading...']);
188 }).toErrorDev([
189 'Invalid key type. Expected a string, number, symbol, or ' +
190 'boolean, but instead received: Hi,100\n\n' +
@@ -186,7 +192,7 @@ describe('ReactCache', () => {
192 'function as the second argument to createResource().',
193 ]);
194 } else {
189 - expect(Scheduler).toFlushAndYield(['App', 'Loading...']);
195 + await waitForAll(['App', 'Loading...']);
196 }
197 });
198
@@ -204,19 +210,19 @@ describe('ReactCache', () => {
210 unstable_isConcurrent: true,
211 },
212 );
207 - expect(Scheduler).toFlushAndYield([
213 + await waitForAll([
214 'Suspend! [1]',
215 'Suspend! [2]',
216 'Suspend! [3]',
217 'Loading...',
218 ]);
219 jest.advanceTimersByTime(100);
214 - expect(Scheduler).toHaveYielded([
220 + assertLog([
221 'Promise resolved [1]',
222 'Promise resolved [2]',
223 'Promise resolved [3]',
224 ]);
219 - expect(Scheduler).toFlushAndYield([1, 2, 3]);
225 + await waitForAll([1, 2, 3]);
226 expect(root).toMatchRenderedOutput('123');
227
228 // Render 1, 4, 5
@@ -228,18 +234,10 @@ describe('ReactCache', () => {
234 </Suspense>,
235 );
236
231 - expect(Scheduler).toFlushAndYield([
232 - 1,
233 - 'Suspend! [4]',
234 - 'Suspend! [5]',
235 - 'Loading...',
236 - ]);
237 + await waitForAll([1, 'Suspend! [4]', 'Suspend! [5]', 'Loading...']);
238 jest.advanceTimersByTime(100);
238 - expect(Scheduler).toHaveYielded([
239 - 'Promise resolved [4]',
240 - 'Promise resolved [5]',
241 - ]);
242 - expect(Scheduler).toFlushAndYield([1, 4, 5]);
239 + assertLog(['Promise resolved [4]', 'Promise resolved [5]']);
240 + await waitForAll([1, 4, 5]);
241 expect(root).toMatchRenderedOutput('145');
242
243 // We've now rendered values 1, 2, 3, 4, 5, over our limit of 3. The least
@@ -253,7 +251,7 @@ describe('ReactCache', () => {
251 </Suspense>,
252 );
253
256 - expect(Scheduler).toFlushAndYield([
254 + await waitForAll([
255 // 1 is still cached
256 1,
257 // 2 and 3 suspend because they were evicted from the cache
@@ -262,11 +260,8 @@ describe('ReactCache', () => {
260 'Loading...',
261 ]);
262 jest.advanceTimersByTime(100);
265 - expect(Scheduler).toHaveYielded([
266 - 'Promise resolved [2]',
267 - 'Promise resolved [3]',
268 - ]);
269 - expect(Scheduler).toFlushAndYield([1, 2, 3]);
263 + assertLog(['Promise resolved [2]', 'Promise resolved [3]']);
264 + await waitForAll([1, 2, 3]);
265 expect(root).toMatchRenderedOutput('123');
266 });
267
@@ -287,18 +282,15 @@ describe('ReactCache', () => {
282 },
283 );
284
290 - expect(Scheduler).toFlushAndYield(['Loading...']);
285 + await waitForAll(['Loading...']);
286
287 jest.advanceTimersByTime(1000);
293 - expect(Scheduler).toHaveYielded([
294 - 'Promise resolved [B]',
295 - 'Promise resolved [A]',
296 - ]);
297 - expect(Scheduler).toFlushAndYield(['Result']);
288 + assertLog(['Promise resolved [B]', 'Promise resolved [A]']);
289 + await waitForAll(['Result']);
290 expect(root).toMatchRenderedOutput('Result');
291 });
292
301 - it('if a thenable resolves multiple times, does not update the first cached value', () => {
293 + it('if a thenable resolves multiple times, does not update the first cached value', async () => {
294 let resolveThenable;
295 const BadTextResource = createResource(
296 ([text, ms = 0]) => {
@@ -349,7 +341,7 @@ describe('ReactCache', () => {
341 },
342 );
343
352 - expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
344 + await waitForAll(['Suspend! [Hi]', 'Loading...']);
345
346 resolveThenable('Hi');
347 // This thenable improperly resolves twice. We should not update the
@@ -365,8 +357,8 @@ describe('ReactCache', () => {
357 },
358 );
359
368 - expect(Scheduler).toHaveYielded([]);
369 - expect(Scheduler).toFlushAndYield(['Hi']);
360 + assertLog([]);
361 + await waitForAll(['Hi']);
362 expect(root).toMatchRenderedOutput('Hi');
363 });
364
packages/react-client/src/__tests__/ReactFlight-test.js
+9 -6
@@ -20,6 +20,7 @@ let ReactNoopFlightClient;
20 let ErrorBoundary;
21 let NoErrorExpected;
22 let Scheduler;
23 +let assertLog;
24
25 describe('ReactFlight', () => {
26 beforeEach(() => {
@@ -33,6 +34,8 @@ describe('ReactFlight', () => {
34 ReactNoopFlightClient = require('react-noop-renderer/flight-client');
35 act = require('jest-react').act;
36 Scheduler = require('scheduler');
37 + const InternalTestUtils = require('internal-test-utils');
38 + assertLog = InternalTestUtils.assertLog;
39
40 ErrorBoundary = class extends React.Component {
41 state = {hasError: false, error: null};
@@ -808,13 +811,13 @@ describe('ReactFlight', () => {
811 const ClientDoublerModuleRef = clientReference(ClientDoubler);
812
813 const transport = ReactNoopFlightServer.render(<App />);
811 - expect(Scheduler).toHaveYielded([]);
814 + assertLog([]);
815
816 await act(async () => {
817 ReactNoop.render(await ReactNoopFlightClient.read(transport));
818 });
819
817 - expect(Scheduler).toHaveYielded(['ClientDoubler']);
820 + assertLog(['ClientDoubler']);
821 expect(ReactNoop).toMatchRenderedOutput(
822 <>
823 <div prop=":S1:">:S1:</div>
@@ -997,7 +1000,7 @@ describe('ReactFlight', () => {
1000
1001 const transport = ReactNoopFlightServer.render(<Foo />);
1002
1000 - expect(Scheduler).toHaveYielded(['suspended']);
1003 + assertLog(['suspended']);
1004
1005 await act(async () => {
1006 resolve();
@@ -1005,7 +1008,7 @@ describe('ReactFlight', () => {
1008 jest.runAllImmediates();
1009 });
1010
1008 - expect(Scheduler).toHaveYielded(['rendered']);
1011 + assertLog(['rendered']);
1012
1013 await act(async () => {
1014 ServerContext._currentRenderer = null;
@@ -1045,7 +1048,7 @@ describe('ReactFlight', () => {
1048
1049 const transport = ReactNoopFlightServer.render(model);
1050
1048 - expect(Scheduler).toHaveYielded([]);
1051 + assertLog([]);
1052
1053 await act(async () => {
1054 ServerContext._currentRenderer = null;
@@ -1054,7 +1057,7 @@ describe('ReactFlight', () => {
1057 ReactNoop.render(flightModel.foo);
1058 });
1059
1057 - expect(Scheduler).toHaveYielded(['ClientBar']);
1060 + assertLog(['ClientBar']);
1061 expect(ReactNoop).toMatchRenderedOutput(<span>hi this is server</span>);
1062
1063 expect(() => {
packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js
+5 -1
@@ -19,6 +19,7 @@ describe('React hooks DevTools integration', () => {
19 let overrideHookState;
20 let scheduleUpdate;
21 let setSuspenseHandler;
22 + let waitForAll;
23
24 global.IS_REACT_ACT_ENVIRONMENT = true;
25
@@ -41,6 +42,9 @@ describe('React hooks DevTools integration', () => {
42 ReactTestRenderer = require('react-test-renderer');
43 Scheduler = require('scheduler');
44
45 + const InternalTestUtils = require('internal-test-utils');
46 + waitForAll = InternalTestUtils.waitForAll;
47 +
48 act = ReactTestRenderer.act;
49 });
50
@@ -256,7 +260,7 @@ describe('React hooks DevTools integration', () => {
260 ),
261 );
262
259 - expect(Scheduler).toFlushAndYield([]);
263 + await waitForAll([]);
264 // Ensure we timeout any suspense time.
265 jest.advanceTimersByTime(1000);
266 const fiber = renderer.root._currentFiber().child;
packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js
+83 -69
@@ -20,6 +20,10 @@ describe('Timeline profiler', () => {
20 let store;
21 let unmountFns;
22 let utils;
23 + let waitFor;
24 + let waitForAll;
25 + let waitForPaint;
26 + let assertLog;
27
28 beforeEach(() => {
29 utils = require('./utils');
@@ -44,6 +48,12 @@ describe('Timeline profiler', () => {
48 ReactDOMClient = require('react-dom/client');
49 Scheduler = require('scheduler');
50
51 + const InternalTestUtils = require('internal-test-utils');
52 + waitFor = InternalTestUtils.waitFor;
53 + waitForAll = InternalTestUtils.waitForAll;
54 + waitForPaint = InternalTestUtils.waitForPaint;
55 + assertLog = InternalTestUtils.assertLog;
56 +
57 store = global.store;
58 });
59
@@ -151,7 +161,7 @@ describe('Timeline profiler', () => {
161 `);
162 });
163
154 - it('should mark concurrent render without suspends or state updates', () => {
164 + it('should mark concurrent render without suspends or state updates', async () => {
165 renderRootHelper(<div />);
166
167 expect(clearedMarks).toMatchInlineSnapshot(`
@@ -162,7 +172,7 @@ describe('Timeline profiler', () => {
172
173 clearPendingMarks();
174
165 - expect(Scheduler).toFlushUntilNextPaint([]);
175 + await waitForPaint([]);
176
177 expect(clearedMarks).toMatchInlineSnapshot(`
178 [
@@ -196,8 +206,7 @@ describe('Timeline profiler', () => {
206 renderRootHelper(<Foo />);
207 });
208
199 - // Do one step of work.
200 - expect(Scheduler).toFlushAndYieldThrough(['Foo']);
209 + await waitFor(['Foo']);
210
211 expect(clearedMarks).toMatchInlineSnapshot(`
212 [
@@ -291,7 +300,11 @@ describe('Timeline profiler', () => {
300 });
301
302 it('should mark concurrent render with suspense that resolves', async () => {
294 - const fakeSuspensePromise = Promise.resolve(true);
303 + let resolveFakePromise;
304 + const fakeSuspensePromise = new Promise(
305 + resolve => (resolveFakePromise = resolve),
306 + );
307 +
308 function Example() {
309 throw fakeSuspensePromise;
310 }
@@ -310,7 +323,7 @@ describe('Timeline profiler', () => {
323
324 clearPendingMarks();
325
313 - expect(Scheduler).toFlushUntilNextPaint([]);
326 + await waitForPaint([]);
327
328 expect(clearedMarks).toMatchInlineSnapshot(`
329 [
@@ -333,7 +346,7 @@ describe('Timeline profiler', () => {
346
347 clearPendingMarks();
348
336 - await fakeSuspensePromise;
349 + await resolveFakePromise();
350 expect(clearedMarks).toMatchInlineSnapshot(`
351 [
352 "--suspense-resolved-0-Example",
@@ -342,7 +355,11 @@ describe('Timeline profiler', () => {
355 });
356
357 it('should mark concurrent render with suspense that rejects', async () => {
345 - const fakeSuspensePromise = Promise.reject(new Error('error'));
358 + let rejectFakePromise;
359 + const fakeSuspensePromise = new Promise(
360 + (_, reject) => (rejectFakePromise = reject),
361 + );
362 +
363 function Example() {
364 throw fakeSuspensePromise;
365 }
@@ -361,7 +378,7 @@ describe('Timeline profiler', () => {
378
379 clearPendingMarks();
380
364 - expect(Scheduler).toFlushUntilNextPaint([]);
381 + await waitForPaint([]);
382
383 expect(clearedMarks).toMatchInlineSnapshot(`
384 [
@@ -384,7 +401,10 @@ describe('Timeline profiler', () => {
401
402 clearPendingMarks();
403
387 - await expect(fakeSuspensePromise).rejects.toThrow();
404 + await expect(() => {
405 + rejectFakePromise(new Error('error'));
406 + return fakeSuspensePromise;
407 + }).rejects.toThrow();
408 expect(clearedMarks).toMatchInlineSnapshot(`
409 [
410 "--suspense-rejected-0-Example",
@@ -392,7 +412,7 @@ describe('Timeline profiler', () => {
412 `);
413 });
414
395 - it('should mark cascading class component state updates', () => {
415 + it('should mark cascading class component state updates', async () => {
416 class Example extends React.Component {
417 state = {didMount: false};
418 componentDidMount() {
@@ -413,7 +433,7 @@ describe('Timeline profiler', () => {
433
434 clearPendingMarks();
435
416 - expect(Scheduler).toFlushUntilNextPaint([]);
436 + await waitForPaint([]);
437
438 expect(clearedMarks).toMatchInlineSnapshot(`
439 [
@@ -446,7 +466,7 @@ describe('Timeline profiler', () => {
466 `);
467 });
468
449 - it('should mark cascading class component force updates', () => {
469 + it('should mark cascading class component force updates', async () => {
470 class Example extends React.Component {
471 componentDidMount() {
472 this.forceUpdate();
@@ -466,7 +486,7 @@ describe('Timeline profiler', () => {
486
487 clearPendingMarks();
488
469 - expect(Scheduler).toFlushUntilNextPaint([]);
489 + await waitForPaint([]);
490
491 expect(clearedMarks).toMatchInlineSnapshot(`
492 [
@@ -499,7 +519,7 @@ describe('Timeline profiler', () => {
519 `);
520 });
521
502 - it('should mark render phase state updates for class component', () => {
522 + it('should mark render phase state updates for class component', async () => {
523 class Example extends React.Component {
524 state = {didRender: false};
525 render() {
@@ -525,7 +545,7 @@ describe('Timeline profiler', () => {
545 errorMessage = message;
546 });
547
528 - expect(Scheduler).toFlushUntilNextPaint([]);
548 + await waitForPaint([]);
549
550 expect(console.error).toHaveBeenCalledTimes(1);
551 expect(errorMessage).toContain(
@@ -552,7 +572,7 @@ describe('Timeline profiler', () => {
572 `);
573 });
574
555 - it('should mark render phase force updates for class component', () => {
575 + it('should mark render phase force updates for class component', async () => {
576 let forced = false;
577 class Example extends React.Component {
578 render() {
@@ -579,7 +599,7 @@ describe('Timeline profiler', () => {
599 errorMessage = message;
600 });
601
582 - expect(Scheduler).toFlushUntilNextPaint([]);
602 + await waitForPaint([]);
603
604 expect(console.error).toHaveBeenCalledTimes(1);
605 expect(errorMessage).toContain(
@@ -606,7 +626,7 @@ describe('Timeline profiler', () => {
626 `);
627 });
628
609 - it('should mark cascading layout updates', () => {
629 + it('should mark cascading layout updates', async () => {
630 function Example() {
631 const [didMount, setDidMount] = React.useState(false);
632 React.useLayoutEffect(() => {
@@ -625,7 +645,7 @@ describe('Timeline profiler', () => {
645
646 clearPendingMarks();
647
628 - expect(Scheduler).toFlushUntilNextPaint([]);
648 + await waitForPaint([]);
649
650 expect(clearedMarks).toMatchInlineSnapshot(`
651 [
@@ -660,7 +680,7 @@ describe('Timeline profiler', () => {
680 `);
681 });
682
663 - it('should mark cascading passive updates', () => {
683 + it('should mark cascading passive updates', async () => {
684 function Example() {
685 const [didMount, setDidMount] = React.useState(false);
686 React.useEffect(() => {
@@ -671,7 +691,7 @@ describe('Timeline profiler', () => {
691
692 renderRootHelper(<Example />);
693
674 - expect(Scheduler).toFlushAndYield([]);
694 + await waitForAll([]);
695
696 expect(clearedMarks).toMatchInlineSnapshot(`
697 [
@@ -709,7 +729,7 @@ describe('Timeline profiler', () => {
729 `);
730 });
731
712 - it('should mark render phase updates', () => {
732 + it('should mark render phase updates', async () => {
733 function Example() {
734 const [didRender, setDidRender] = React.useState(false);
735 if (!didRender) {
@@ -720,7 +740,7 @@ describe('Timeline profiler', () => {
740
741 renderRootHelper(<Example />);
742
723 - expect(Scheduler).toFlushAndYield([]);
743 + await waitForAll([]);
744
745 expect(clearedMarks).toMatchInlineSnapshot(`
746 [
@@ -840,7 +860,7 @@ describe('Timeline profiler', () => {
860
861 clearPendingMarks();
862
843 - expect(Scheduler).toFlushUntilNextPaint([]);
863 + await waitForPaint([]);
864
865 expect(clearedMarks).toMatchInlineSnapshot(`
866 [
@@ -927,10 +947,7 @@ describe('Timeline profiler', () => {
947
948 const unmount = renderRootHelper(<ComponentWithEffects />);
949
930 - expect(Scheduler).toFlushUntilNextPaint([
931 - 'layout 1 mount',
932 - 'layout 2 mount',
933 - ]);
950 + await waitForPaint(['layout 1 mount', 'layout 2 mount']);
951
952 expect(clearedMarks).toMatchInlineSnapshot(`
953 [
@@ -957,7 +974,7 @@ describe('Timeline profiler', () => {
974
975 clearPendingMarks();
976
960 - expect(Scheduler).toFlushAndYield([
977 + await waitForAll([
978 'passive 1 mount',
979 'passive 2 mount',
980 'passive 3 mount',
@@ -978,11 +995,11 @@ describe('Timeline profiler', () => {
995
996 clearPendingMarks();
997
981 - expect(Scheduler).toFlushAndYield([]);
998 + await waitForAll([]);
999
1000 unmount();
1001
985 - expect(Scheduler).toHaveYielded([
1002 + assertLog([
1003 'layout 1 unmount',
1004 'layout 2 unmount',
1005 'passive 1 unmount',
@@ -1063,7 +1080,7 @@ describe('Timeline profiler', () => {
1080 }
1081
1082 renderRootHelper(<App />);
1066 - expect(Scheduler).toFlushAndYield([]);
1083 + await waitForAll([]);
1084
1085 clearedMarks.splice(0);
1086
@@ -1102,7 +1119,7 @@ describe('Timeline profiler', () => {
1119 }
1120
1121 renderRootHelper(<App />);
1105 - expect(Scheduler).toFlushAndYield([]);
1122 + await waitForAll([]);
1123
1124 clearedMarks.splice(0);
1125
@@ -1110,7 +1127,7 @@ describe('Timeline profiler', () => {
1127 event.initEvent('mouseover', true, true);
1128 dispatchAndSetCurrentEvent(targetRef.current, event);
1129
1113 - expect(Scheduler).toFlushAndYield([]);
1130 + await waitForAll([]);
1131
1132 expect(clearedMarks).toMatchInlineSnapshot(`
1133 [
@@ -1324,11 +1341,11 @@ describe('Timeline profiler', () => {
1341 });
1342
1343 // Do one step of work.
1327 - expect(Scheduler).toFlushAndYieldThrough(['Foo']);
1344 + await waitFor(['Foo']);
1345
1346 // Finish flushing so React commits;
1347 // Unless we do this, the ProfilerStore won't collect Profiling data.
1331 - expect(Scheduler).toFlushAndYield(['Bar']);
1348 + await waitForAll(['Bar']);
1349
1350 // Since we yielded, the batch should report two separate "render" chunks.
1351 const batch = getBatchOfWork(0);
@@ -1359,13 +1376,13 @@ describe('Timeline profiler', () => {
1376 </React.Suspense>,
1377 );
1378
1362 - expect(Scheduler).toHaveYielded(['suspended']);
1379 + assertLog(['suspended']);
1380
1381 Scheduler.unstable_advanceTime(10);
1382 resolveFn();
1383 await suspensePromise;
1384
1368 - expect(Scheduler).toFlushAndYield(['resolved']);
1385 + await waitForAll(['resolved']);
1386
1387 const timelineData = stopProfilingAndGetTimelineData();
1388
@@ -1417,13 +1434,13 @@ describe('Timeline profiler', () => {
1434 </React.Suspense>,
1435 );
1436
1420 - expect(Scheduler).toHaveYielded(['suspended']);
1437 + assertLog(['suspended']);
1438
1439 Scheduler.unstable_advanceTime(10);
1440 rejectFn();
1441 await expect(suspensePromise).rejects.toThrow();
1442
1426 - expect(Scheduler).toHaveYielded(['rejected']);
1443 + assertLog(['rejected']);
1444
1445 const timelineData = stopProfilingAndGetTimelineData();
1446
@@ -1475,13 +1492,13 @@ describe('Timeline profiler', () => {
1492 </React.Suspense>,
1493 );
1494
1478 - expect(Scheduler).toFlushAndYield(['suspended']);
1495 + await waitForAll(['suspended']);
1496
1497 Scheduler.unstable_advanceTime(10);
1498 resolveFn();
1499 await suspensePromise;
1500
1484 - expect(Scheduler).toFlushAndYield(['resolved']);
1501 + await waitForAll(['resolved']);
1502
1503 const timelineData = stopProfilingAndGetTimelineData();
1504
@@ -1533,13 +1550,13 @@ describe('Timeline profiler', () => {
1550 </React.Suspense>,
1551 );
1552
1536 - expect(Scheduler).toFlushAndYield(['suspended']);
1553 + await waitForAll(['suspended']);
1554
1555 Scheduler.unstable_advanceTime(10);
1556 rejectFn();
1557 await expect(suspensePromise).rejects.toThrow();
1558
1542 - expect(Scheduler).toFlushAndYield(['rejected']);
1559 + await waitForAll(['rejected']);
1560
1561 const timelineData = stopProfilingAndGetTimelineData();
1562
@@ -1566,7 +1583,7 @@ describe('Timeline profiler', () => {
1583 expect(timelineData.componentMeasures).toHaveLength(2);
1584 });
1585
1569 - it('should mark cascading class component state updates', () => {
1586 + it('should mark cascading class component state updates', async () => {
1587 class Example extends React.Component {
1588 state = {didMount: false};
1589 componentDidMount() {
@@ -1583,7 +1600,7 @@ describe('Timeline profiler', () => {
1600
1601 renderRootHelper(<Example />);
1602
1586 - expect(Scheduler).toFlushUntilNextPaint(['mount', 'update']);
1603 + await waitForPaint(['mount', 'update']);
1604
1605 const timelineData = stopProfilingAndGetTimelineData();
1606 expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
@@ -1626,7 +1643,7 @@ describe('Timeline profiler', () => {
1643 `);
1644 });
1645
1629 - it('should mark cascading class component force updates', () => {
1646 + it('should mark cascading class component force updates', async () => {
1647 let forced = false;
1648 class Example extends React.Component {
1649 componentDidMount() {
@@ -1642,7 +1659,7 @@ describe('Timeline profiler', () => {
1659
1660 renderRootHelper(<Example />);
1661
1645 - expect(Scheduler).toFlushUntilNextPaint(['mount', 'force update']);
1662 + await waitForPaint(['mount', 'force update']);
1663
1664 const timelineData = stopProfilingAndGetTimelineData();
1665 expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
@@ -1683,7 +1700,7 @@ describe('Timeline profiler', () => {
1700 `);
1701 });
1702
1686 - it('should mark render phase state updates for class component', () => {
1703 + it('should mark render phase state updates for class component', async () => {
1704 class Example extends React.Component {
1705 state = {didRender: false};
1706 render() {
@@ -1705,7 +1722,7 @@ describe('Timeline profiler', () => {
1722 errorMessage = message;
1723 });
1724
1708 - expect(Scheduler).toFlushAndYield(['first render', 'second render']);
1725 + await waitForAll(['first render', 'second render']);
1726
1727 expect(console.error).toHaveBeenCalledTimes(1);
1728 expect(errorMessage).toContain(
@@ -1753,7 +1770,7 @@ describe('Timeline profiler', () => {
1770 `);
1771 });
1772
1756 - it('should mark render phase force updates for class component', () => {
1773 + it('should mark render phase force updates for class component', async () => {
1774 let forced = false;
1775 class Example extends React.Component {
1776 render() {
@@ -1774,7 +1791,7 @@ describe('Timeline profiler', () => {
1791 errorMessage = message;
1792 });
1793
1777 - expect(Scheduler).toFlushAndYield(['render', 'force update']);
1794 + await waitForAll(['render', 'force update']);
1795
1796 expect(console.error).toHaveBeenCalledTimes(1);
1797 expect(errorMessage).toContain(
@@ -1820,7 +1837,7 @@ describe('Timeline profiler', () => {
1837 `);
1838 });
1839
1823 - it('should mark cascading layout updates', () => {
1840 + it('should mark cascading layout updates', async () => {
1841 function Example() {
1842 const [didMount, setDidMount] = React.useState(false);
1843 React.useLayoutEffect(() => {
@@ -1834,7 +1851,7 @@ describe('Timeline profiler', () => {
1851
1852 renderRootHelper(<Example />);
1853
1837 - expect(Scheduler).toFlushAndYield(['mount', 'update']);
1854 + await waitForAll(['mount', 'update']);
1855
1856 const timelineData = stopProfilingAndGetTimelineData();
1857 expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
@@ -1884,7 +1901,7 @@ describe('Timeline profiler', () => {
1901 `);
1902 });
1903
1887 - it('should mark cascading passive updates', () => {
1904 + it('should mark cascading passive updates', async () => {
1905 function Example() {
1906 const [didMount, setDidMount] = React.useState(false);
1907 React.useEffect(() => {
@@ -1897,7 +1914,7 @@ describe('Timeline profiler', () => {
1914 }
1915
1916 renderRootHelper(<Example />);
1900 - expect(Scheduler).toFlushAndYield(['mount', 'update']);
1917 + await waitForAll(['mount', 'update']);
1918
1919 const timelineData = stopProfilingAndGetTimelineData();
1920 expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
@@ -1947,7 +1964,7 @@ describe('Timeline profiler', () => {
1964 `);
1965 });
1966
1950 - it('should mark render phase updates', () => {
1967 + it('should mark render phase updates', async () => {
1968 function Example() {
1969 const [didRender, setDidRender] = React.useState(false);
1970 Scheduler.unstable_advanceTime(10);
@@ -1959,7 +1976,7 @@ describe('Timeline profiler', () => {
1976 }
1977
1978 renderRootHelper(<Example />);
1962 - expect(Scheduler).toFlushAndYield(['mount', 'update']);
1979 + await waitForAll(['mount', 'update']);
1980
1981 const timelineData = stopProfilingAndGetTimelineData();
1982 // Render phase updates should be retried as part of the same batch.
@@ -2026,7 +2043,7 @@ describe('Timeline profiler', () => {
2043 </ErrorBoundary>,
2044 );
2045
2029 - expect(Scheduler).toHaveYielded([
2046 + assertLog([
2047 'ErrorBoundary render',
2048 'ExampleThatThrows',
2049 'ExampleThatThrows',
@@ -2122,7 +2139,7 @@ describe('Timeline profiler', () => {
2139 </ErrorBoundary>,
2140 );
2141
2125 - expect(Scheduler).toFlushAndYield([
2142 + await waitForAll([
2143 'ErrorBoundary render',
2144 'ExampleThatThrows',
2145 'ExampleThatThrows',
@@ -2253,22 +2270,19 @@ describe('Timeline profiler', () => {
2270
2271 const unmount = renderRootHelper(<ComponentWithEffects />);
2272
2256 - expect(Scheduler).toFlushUntilNextPaint([
2257 - 'layout 1 mount',
2258 - 'layout 2 mount',
2259 - ]);
2273 + await waitForPaint(['layout 1 mount', 'layout 2 mount']);
2274
2261 - expect(Scheduler).toFlushAndYield([
2275 + await waitForAll([
2276 'passive 1 mount',
2277 'passive 2 mount',
2278 'passive 3 mount',
2279 ]);
2280
2267 - expect(Scheduler).toFlushAndYield([]);
2281 + await waitForAll([]);
2282
2283 unmount();
2284
2271 - expect(Scheduler).toHaveYielded([
2285 + assertLog([
2286 'layout 1 unmount',
2287 'layout 2 unmount',
2288 'passive 1 unmount',
@@ -2465,7 +2479,7 @@ describe('Timeline profiler', () => {
2479
2480 renderRootHelper(<CommponentWithChildren initialRender={false} />);
2481
2468 - expect(Scheduler).toFlushAndYield([
2482 + await waitForAll([
2483 'Render ComponentWithChildren',
2484 'Render Child',
2485 'Render Child',
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
+6 -2
@@ -15,6 +15,7 @@ let ReactDOM;
15 let ReactDOMClient;
16 let Scheduler;
17 let act;
18 +let waitForAll;
19
20 const setUntrackedInputValue = Object.getOwnPropertyDescriptor(
21 HTMLInputElement.prototype,
@@ -33,6 +34,9 @@ describe('ReactDOMFiberAsync', () => {
34 act = require('jest-react').act;
35 Scheduler = require('scheduler');
36
37 + const InternalTestUtils = require('internal-test-utils');
38 + waitForAll = InternalTestUtils.waitForAll;
39 +
40 document.body.appendChild(container);
41 });
42
@@ -592,7 +596,7 @@ describe('ReactDOMFiberAsync', () => {
596 expect(containerC.textContent).toEqual('Finished');
597 });
598
595 - it('updates flush without yielding in the next event', () => {
599 + it('updates flush without yielding in the next event', async () => {
600 const root = ReactDOMClient.createRoot(container);
601
602 function Text(props) {
@@ -612,7 +616,7 @@ describe('ReactDOMFiberAsync', () => {
616 expect(container.textContent).toEqual('');
617
618 // Everything should render immediately in the next event
615 - expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
619 + await waitForAll(['A', 'B', 'C']);
620 expect(container.textContent).toEqual('ABC');
621 });
622
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+88 -78
@@ -38,6 +38,10 @@ let buffer = '';
38 let hasErrored = false;
39 let fatalError = undefined;
40 let renderOptions;
41 +let waitFor;
42 +let waitForAll;
43 +let assertLog;
44 +let waitForPaint;
45
46 function resetJSDOM(markup) {
47 // Test Environment
@@ -65,6 +69,12 @@ describe('ReactDOMFizzServer', () => {
69
70 PropTypes = require('prop-types');
71
72 + const InternalTestUtils = require('internal-test-utils');
73 + waitForAll = InternalTestUtils.waitForAll;
74 + waitFor = InternalTestUtils.waitFor;
75 + waitForPaint = InternalTestUtils.waitForPaint;
76 + assertLog = InternalTestUtils.assertLog;
77 +
78 if (gate(flags => flags.source)) {
79 // The `with-selector` module composes the main `use-sync-external-store`
80 // entrypoint. In the compiled artifacts, this is resolved to the `shim`
@@ -562,7 +572,7 @@ describe('ReactDOMFizzServer', () => {
572 expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
573
574 // Now we can client render it instead.
565 - expect(Scheduler).toFlushAndYield([]);
575 + await waitForAll([]);
576 expectErrors(
577 errors,
578 [
@@ -684,7 +694,7 @@ describe('ReactDOMFizzServer', () => {
694 expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
695
696 // Now we can client render it instead.
687 - expect(Scheduler).toFlushAndYield([]);
697 + await waitForAll([]);
698
699 expectErrors(
700 errors,
@@ -843,7 +853,7 @@ describe('ReactDOMFizzServer', () => {
853 expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
854
855 // Now we can client render it instead.
846 - expect(Scheduler).toFlushAndYield([]);
856 + await waitForAll([]);
857
858 expectErrors(
859 errors,
@@ -1161,7 +1171,7 @@ describe('ReactDOMFizzServer', () => {
1171 });
1172
1173 // We still can't render it on the client.
1164 - expect(Scheduler).toFlushAndYield([]);
1174 + await waitForAll([]);
1175 expectErrors(
1176 errors,
1177 [
@@ -1883,7 +1893,7 @@ describe('ReactDOMFizzServer', () => {
1893 expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
1894
1895 // That will let us client render it instead.
1886 - expect(Scheduler).toFlushAndYield([]);
1896 + await waitForAll([]);
1897 expectErrors(
1898 errors,
1899 [
@@ -2139,7 +2149,7 @@ describe('ReactDOMFizzServer', () => {
2149 );
2150 pipe(writable);
2151 });
2142 - expect(Scheduler).toHaveYielded(['server']);
2152 + assertLog(['server']);
2153
2154 ReactDOMClient.hydrateRoot(container, <App />, {
2155 onRecoverableError(error) {
@@ -2149,9 +2159,9 @@ describe('ReactDOMFizzServer', () => {
2159 },
2160 });
2161
2152 - expect(() => {
2162 + await expect(async () => {
2163 // The first paint switches to client rendering due to mismatch
2154 - expect(Scheduler).toFlushUntilNextPaint([
2164 + await waitForPaint([
2165 'client',
2166 'Log recoverable error: Hydration failed because the initial ' +
2167 'UI does not match what was rendered on the server.',
@@ -2224,7 +2234,7 @@ describe('ReactDOMFizzServer', () => {
2234 );
2235 pipe(writable);
2236 });
2227 - expect(Scheduler).toHaveYielded(['server']);
2237 + assertLog(['server']);
2238
2239 ReactDOMClient.hydrateRoot(container, <App />, {
2240 onRecoverableError(error) {
@@ -2235,9 +2245,9 @@ describe('ReactDOMFizzServer', () => {
2245 });
2246
2247 // The first paint uses the client due to mismatch forcing client render
2238 - expect(() => {
2248 + await expect(async () => {
2249 // The first paint switches to client rendering due to mismatch
2240 - expect(Scheduler).toFlushUntilNextPaint([
2250 + await waitForPaint([
2251 'client',
2252 'Log recoverable error: Hydration failed because the initial ' +
2253 'UI does not match what was rendered on the server.',
@@ -2304,7 +2314,7 @@ describe('ReactDOMFizzServer', () => {
2314 const {pipe} = renderToPipeableStream(<App />);
2315 pipe(writable);
2316 });
2307 - expect(Scheduler).toHaveYielded(['Yay!']);
2317 + assertLog(['Yay!']);
2318
2319 const span = container.getElementsByTagName('span')[0];
2320
@@ -2319,8 +2329,8 @@ describe('ReactDOMFizzServer', () => {
2329
2330 // An error logged but instead of surfacing it to the UI, we switched
2331 // to client rendering.
2322 - expect(() => {
2323 - expect(Scheduler).toFlushAndYield([
2332 + await expect(async () => {
2333 + await waitForAll([
2334 'Yay!',
2335 'Hydration error',
2336 'There was an error while hydrating. Because the error happened ' +
@@ -2394,7 +2404,7 @@ describe('ReactDOMFizzServer', () => {
2404 const {pipe} = renderToPipeableStream(<App />);
2405 pipe(writable);
2406 });
2397 - expect(Scheduler).toHaveYielded(['Yay!']);
2407 + assertLog(['Yay!']);
2408
2409 const [span1, span2, span3] = container.getElementsByTagName('span');
2410
@@ -2409,7 +2419,7 @@ describe('ReactDOMFizzServer', () => {
2419
2420 // An error logged but instead of surfacing it to the UI, we switched
2421 // to client rendering.
2412 - expect(Scheduler).toFlushAndYield([
2422 + await waitForAll([
2423 'Yay!',
2424 'Hydration error',
2425 'There was an error while hydrating this Suspense boundary. Switched to client rendering.',
@@ -2484,7 +2494,7 @@ describe('ReactDOMFizzServer', () => {
2494 const {pipe} = renderToPipeableStream(<App />);
2495 pipe(writable);
2496 });
2487 - expect(Scheduler).toHaveYielded(['Yay!']);
2497 + assertLog(['Yay!']);
2498
2499 // Hydrate the tree. Child will throw during render.
2500 isClient = true;
@@ -2497,7 +2507,7 @@ describe('ReactDOMFizzServer', () => {
2507
2508 // Because we failed to recover from the error, onRecoverableError
2509 // shouldn't be called.
2500 - expect(Scheduler).toFlushAndYield([]);
2510 + await waitForAll([]);
2511 expect(getVisibleChildren(container)).toEqual('Oops!');
2512
2513 expectErrors(errors, [], []);
@@ -2541,7 +2551,7 @@ describe('ReactDOMFizzServer', () => {
2551 });
2552 pipe(writable);
2553 });
2544 - expect(Scheduler).toHaveYielded(['[s!] Oops.']);
2554 + assertLog(['[s!] Oops.']);
2555
2556 // The server could not complete this boundary, so we'll retry on the client.
2557 const serverFallback = container.getElementsByTagName('p')[0];
@@ -2555,7 +2565,7 @@ describe('ReactDOMFizzServer', () => {
2565 },
2566 });
2567 // This should not report any errors yet.
2558 - expect(Scheduler).toFlushAndYield([]);
2568 + await waitForAll([]);
2569 expect(getVisibleChildren(container)).toEqual(
2570 <div>
2571 <p>Loading...</p>
@@ -2573,7 +2583,7 @@ describe('ReactDOMFizzServer', () => {
2583 await act(async () => {
2584 resolveText('Yay!');
2585 });
2576 - expect(Scheduler).toFlushAndYield([
2586 + await waitForAll([
2587 'Yay!',
2588 '[c!] The server could not finish this Suspense boundary, ' +
2589 'likely due to an error during server rendering. ' +
@@ -2626,7 +2636,7 @@ describe('ReactDOMFizzServer', () => {
2636 });
2637 pipe(writable);
2638 });
2629 - expect(Scheduler).toHaveYielded(['[s!] Oops.']);
2639 + assertLog(['[s!] Oops.']);
2640
2641 // The server could not complete this boundary, so we'll retry on the client.
2642 const serverFallback = container.getElementsByTagName('p')[0];
@@ -2640,7 +2650,7 @@ describe('ReactDOMFizzServer', () => {
2650 },
2651 });
2652 // This should not report any errors yet.
2643 - expect(Scheduler).toFlushAndYield([]);
2653 + await waitForAll([]);
2654 expect(getVisibleChildren(container)).toEqual(
2655 <div>
2656 <p>Loading...</p>
@@ -2667,7 +2677,7 @@ describe('ReactDOMFizzServer', () => {
2677 await act(async () => {
2678 resolveText('Yay!');
2679 });
2670 - expect(Scheduler).toFlushAndYield([
2680 + await waitForAll([
2681 'Yay! (red)',
2682 '[c!] The server could not finish this Suspense boundary, ' +
2683 'likely due to an error during server rendering. ' +
@@ -2727,7 +2737,7 @@ describe('ReactDOMFizzServer', () => {
2737 );
2738 pipe(writable);
2739 });
2730 - expect(Scheduler).toHaveYielded(['[s!] Oops.']);
2740 + assertLog(['[s!] Oops.']);
2741
2742 const serverFallback = container.getElementsByTagName('p')[0];
2743 expect(serverFallback.innerHTML).toBe('Loading...');
@@ -2744,7 +2754,7 @@ describe('ReactDOMFizzServer', () => {
2754 },
2755 );
2756 // This should not report any errors yet.
2747 - expect(Scheduler).toFlushAndYield([]);
2757 + await waitForAll([]);
2758 expect(getVisibleChildren(container)).toEqual(
2759 <div>
2760 <p>Loading...</p>
@@ -2763,7 +2773,7 @@ describe('ReactDOMFizzServer', () => {
2773 root.render(<App fallbackText="More loading..." />);
2774 Scheduler.unstable_flushAll();
2775 jest.runAllTimers();
2766 - expect(Scheduler).toHaveYielded([
2776 + assertLog([
2777 '[c!] The server could not finish this Suspense boundary, ' +
2778 'likely due to an error during server rendering. ' +
2779 'Switched to client rendering.',
@@ -2781,7 +2791,7 @@ describe('ReactDOMFizzServer', () => {
2791 await act(async () => {
2792 resolveText('Yay!');
2793 });
2784 - expect(Scheduler).toFlushAndYield(['Yay!']);
2794 + await waitForAll(['Yay!']);
2795 expect(getVisibleChildren(container)).toEqual(
2796 <div>
2797 <span>Yay!</span>
@@ -2849,7 +2859,7 @@ describe('ReactDOMFizzServer', () => {
2859 const {pipe} = renderToPipeableStream(<App />);
2860 pipe(writable);
2861 });
2852 - expect(Scheduler).toHaveYielded(['Yay!']);
2862 + assertLog(['Yay!']);
2863
2864 const [span1, span2, span3] = container.getElementsByTagName('span');
2865
@@ -2864,7 +2874,7 @@ describe('ReactDOMFizzServer', () => {
2874
2875 // An error logged but instead of surfacing it to the UI, we switched
2876 // to client rendering.
2867 - expect(Scheduler).toFlushAndYield([
2877 + await waitForAll([
2878 'Hydration error',
2879 'There was an error while hydrating this Suspense boundary. Switched ' +
2880 'to client rendering.',
@@ -2880,7 +2890,7 @@ describe('ReactDOMFizzServer', () => {
2890 await act(async () => {
2891 resolveText('Yay!');
2892 });
2883 - expect(Scheduler).toFlushAndYield(['Yay!']);
2893 + await waitForAll(['Yay!']);
2894 expect(getVisibleChildren(container)).toEqual(
2895 <div>
2896 <span />
@@ -2937,13 +2947,13 @@ describe('ReactDOMFizzServer', () => {
2947 });
2948
2949 // Partially render A, but yield before the render has finished
2940 - expect(Scheduler).toFlushAndYieldThrough(['Oops!', 'Oops!']);
2950 + await waitFor(['Oops!', 'Oops!']);
2951
2952 // React will try rendering again synchronously. During the retry, A will
2953 // not throw. This simulates a concurrent data race that is fixed by
2954 // blocking the main thread.
2955 shouldThrow = false;
2946 - expect(Scheduler).toFlushAndYield([
2956 + await waitForAll([
2957 // Finish initial render attempt
2958 'B',
2959
@@ -3001,7 +3011,7 @@ describe('ReactDOMFizzServer', () => {
3011 const {pipe} = renderToPipeableStream(<App />);
3012 pipe(writable);
3013 });
3004 - expect(Scheduler).toHaveYielded(['A', 'B']);
3014 + assertLog(['A', 'B']);
3015
3016 // Hydrate the tree. Child will throw during hydration, but not when it
3017 // falls back to client rendering.
@@ -3014,7 +3024,7 @@ describe('ReactDOMFizzServer', () => {
3024 },
3025 });
3026
3017 - expect(Scheduler).toFlushAndYield([
3027 + await waitForAll([
3028 'A',
3029 'B',
3030
@@ -3151,7 +3161,7 @@ describe('ReactDOMFizzServer', () => {
3161 },
3162 });
3163
3154 - expect(Scheduler).toFlushAndYield([]);
3164 + await waitForAll([]);
3165
3166 expectErrors(
3167 errors,
@@ -3232,7 +3242,7 @@ describe('ReactDOMFizzServer', () => {
3242 },
3243 });
3244
3235 - expect(Scheduler).toFlushAndYield([]);
3245 + await waitForAll([]);
3246
3247 expectErrors(
3248 errors,
@@ -3299,7 +3309,7 @@ describe('ReactDOMFizzServer', () => {
3309 },
3310 },
3311 );
3302 - expect(Scheduler).toFlushWithoutYielding();
3312 + await waitForAll([]);
3313 });
3314
3315 describe('error escaping', () => {
@@ -3442,7 +3452,7 @@ describe('ReactDOMFizzServer', () => {
3452 errors.push({error, errorInfo});
3453 },
3454 });
3445 - expect(Scheduler).toFlushAndYield([]);
3455 + await waitForAll([]);
3456
3457 // If escaping were not done we would get a message that says "bad hash"
3458 expectErrors(
@@ -3729,7 +3739,7 @@ describe('ReactDOMFizzServer', () => {
3739 // Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring
3740 // client-side rendering.
3741 await clientResolve();
3732 - expect(Scheduler).toFlushWithoutYielding();
3742 + await waitForAll([]);
3743 expect(getVisibleChildren(container)).toEqual(
3744 <div>
3745 <p>A</p>
@@ -3808,8 +3818,8 @@ describe('ReactDOMFizzServer', () => {
3818 // Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring
3819 // client-side rendering.
3820 await clientResolve();
3811 - expect(() => {
3812 - expect(Scheduler).toFlushAndYield([
3821 + await expect(async () => {
3822 + await waitForAll([
3823 'Logged recoverable error: Text content does not match server-rendered HTML.',
3824 'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.',
3825 ]);
@@ -3823,7 +3833,7 @@ describe('ReactDOMFizzServer', () => {
3833 </div>,
3834 );
3835
3826 - expect(Scheduler).toFlushAndYield([]);
3836 + await waitForAll([]);
3837 });
3838
3839 // @gate enableClientRenderFallbackOnTextMismatch
@@ -3867,7 +3877,7 @@ describe('ReactDOMFizzServer', () => {
3877 );
3878 },
3879 });
3870 - expect(Scheduler).toFlushAndYield([
3880 + await waitForAll([
3881 'Logged recoverable error: Text content does not match server-rendered HTML.',
3882 'Logged recoverable error: Text content does not match server-rendered HTML.',
3883 'Logged recoverable error: Text content does not match server-rendered HTML.',
@@ -3882,7 +3892,7 @@ describe('ReactDOMFizzServer', () => {
3892 </div>,
3893 );
3894
3885 - expect(Scheduler).toFlushAndYield([]);
3895 + await waitForAll([]);
3896 if (__DEV__) {
3897 expect(mockError.mock.calls.length).toBe(1);
3898 expect(mockError.mock.calls[0]).toEqual([
@@ -3958,7 +3968,7 @@ describe('ReactDOMFizzServer', () => {
3968 );
3969 },
3970 });
3961 - expect(Scheduler).toFlushAndYield([
3971 + await waitForAll([
3972 'Logged recoverable error: uh oh',
3973 'Logged recoverable error: Hydration failed because the initial UI does not match what was rendered on the server.',
3974 'Logged recoverable error: Hydration failed because the initial UI does not match what was rendered on the server.',
@@ -3973,7 +3983,7 @@ describe('ReactDOMFizzServer', () => {
3983 </div>,
3984 );
3985
3976 - expect(Scheduler).toFlushAndYield([]);
3986 + await waitForAll([]);
3987 });
3988
3989 // @gate __DEV__
@@ -4050,7 +4060,7 @@ describe('ReactDOMFizzServer', () => {
4060 );
4061 },
4062 });
4053 - expect(Scheduler).toFlushAndYield([
4063 + await waitForAll([
4064 'throwing: first error',
4065 // this repeated first error is the invokeGuardedCallback throw
4066 'throwing: first error',
@@ -4081,7 +4091,7 @@ describe('ReactDOMFizzServer', () => {
4091 </div>,
4092 );
4093
4084 - expect(Scheduler).toFlushAndYield([]);
4094 + await waitForAll([]);
4095 expect(mockError.mock.calls).toEqual([]);
4096 } finally {
4097 console.error = originalConsoleError;
@@ -4181,7 +4191,7 @@ describe('ReactDOMFizzServer', () => {
4191 );
4192 },
4193 });
4184 - expect(Scheduler).toFlushAndYield([
4194 + await waitForAll([
4195 'suspending',
4196 'throwing: first error',
4197 // There is no repeated first error because we already suspended and no
@@ -4202,7 +4212,7 @@ describe('ReactDOMFizzServer', () => {
4212 await unsuspend();
4213 // Since our client components only throw on the very first render there are no
4214 // new throws in this pass
4205 - expect(Scheduler).toFlushAndYield([]);
4215 + await waitForAll([]);
4216
4217 expect(mockError.mock.calls).toEqual([]);
4218 } finally {
@@ -4304,7 +4314,7 @@ describe('ReactDOMFizzServer', () => {
4314 );
4315 },
4316 });
4307 - expect(Scheduler).toFlushAndYield([
4317 + await waitForAll([
4318 'throwing: first error',
4319 // duplicate because first error is re-done in invokeGuardedCallback
4320 'throwing: first error',
@@ -4331,7 +4341,7 @@ describe('ReactDOMFizzServer', () => {
4341 await unsuspend();
4342 // Since our client components only throw on the very first render there are no
4343 // new throws in this pass
4334 - expect(Scheduler).toFlushAndYield([]);
4344 + await waitForAll([]);
4345 expect(mockError.mock.calls).toEqual([]);
4346 } finally {
4347 console.error = originalConsoleError;
@@ -4365,7 +4375,7 @@ describe('ReactDOMFizzServer', () => {
4375 },
4376 });
4377
4368 - expect(Scheduler).toFlushAndYield([]);
4378 + await waitForAll([]);
4379 expect(errors).toEqual([]);
4380 expect(getVisibleChildren(container)).toEqual(
4381 <div>
@@ -4374,7 +4384,7 @@ describe('ReactDOMFizzServer', () => {
4384 );
4385
4386 resolveText('A');
4377 - expect(Scheduler).toFlushAndYield([]);
4387 + await waitForAll([]);
4388 expect(errors).toEqual([]);
4389 expect(getVisibleChildren(container)).toEqual(
4390 <div>
@@ -4411,7 +4421,7 @@ describe('ReactDOMFizzServer', () => {
4421 },
4422 });
4423
4414 - expect(Scheduler).toFlushAndYield([]);
4424 + await waitForAll([]);
4425 expect(errors).toEqual([]);
4426 expect(getVisibleChildren(container)).toEqual(
4427 <div>
@@ -4421,7 +4431,7 @@ describe('ReactDOMFizzServer', () => {
4431 );
4432
4433 resolve({default: () => <p>lazy</p>});
4424 - expect(Scheduler).toFlushAndYield([]);
4434 + await waitForAll([]);
4435 expect(errors).toEqual([]);
4436 expect(getVisibleChildren(container)).toEqual(
4437 <div>
@@ -4566,7 +4576,7 @@ describe('ReactDOMFizzServer', () => {
4576 errors.push(error.message);
4577 },
4578 });
4569 - expect(Scheduler).toFlushAndYield([]);
4579 + await waitForAll([]);
4580 expect(errors).toEqual([]);
4581 expect(getVisibleChildren(container)).toEqual(
4582 <div>
@@ -4629,7 +4639,7 @@ describe('ReactDOMFizzServer', () => {
4639 errors.push(error.message);
4640 },
4641 });
4632 - expect(Scheduler).toFlushAndYield([]);
4642 + await waitForAll([]);
4643 expect(errors).toEqual([]);
4644 expect(getVisibleChildren(container)).toEqual(
4645 <div id="app-div">
@@ -4679,7 +4689,7 @@ describe('ReactDOMFizzServer', () => {
4689 errors.push(error.message);
4690 },
4691 });
4682 - expect(Scheduler).toFlushAndYield([]);
4692 + await waitForAll([]);
4693 expect(errors).toEqual([]);
4694 expect(getVisibleChildren(container)).toEqual(
4695 <div id="app-div">{['h', 'ello', 'w', 'orld']}</div>,
@@ -4724,7 +4734,7 @@ describe('ReactDOMFizzServer', () => {
4734 errors.push(error.message);
4735 },
4736 });
4727 - expect(Scheduler).toFlushAndYield([]);
4737 + await waitForAll([]);
4738 expect(errors).toEqual([]);
4739 expect(getVisibleChildren(container)).toEqual(
4740 <div id="app-div">{['h', 'ello', 'w', 'orld']}</div>,
@@ -4762,7 +4772,7 @@ describe('ReactDOMFizzServer', () => {
4772 errors.push(error.message);
4773 },
4774 });
4765 - expect(Scheduler).toFlushAndYield([]);
4775 + await waitForAll([]);
4776 expect(errors).toEqual([]);
4777 expect(getVisibleChildren(container)).toEqual(
4778 <div>
@@ -4800,7 +4810,7 @@ describe('ReactDOMFizzServer', () => {
4810 errors.push(error.message);
4811 },
4812 });
4803 - expect(Scheduler).toFlushAndYield([]);
4813 + await waitForAll([]);
4814 expect(errors).toEqual([]);
4815 expect(getVisibleChildren(container)).toEqual(
4816 <div>
@@ -4857,7 +4867,7 @@ describe('ReactDOMFizzServer', () => {
4867 errors.push(error.message);
4868 },
4869 });
4860 - expect(Scheduler).toFlushAndYield([]);
4870 + await waitForAll([]);
4871 expect(errors).toEqual([]);
4872 expect(getVisibleChildren(container)).toEqual(
4873 <div id="app-div">
@@ -4883,7 +4893,7 @@ describe('ReactDOMFizzServer', () => {
4893 '<div id="app-div">start<!--$-->firststartfirst suspendedfirstend<!--/$--><!--$-->secondstart<b>second suspended</b><!--/$-->end</div>',
4894 );
4895
4886 - expect(Scheduler).toFlushAndYield([]);
4896 + await waitForAll([]);
4897 expect(errors).toEqual([]);
4898 expect(getVisibleChildren(container)).toEqual(
4899 <div id="app-div">
@@ -4939,7 +4949,7 @@ describe('ReactDOMFizzServer', () => {
4949 errors.push(error.message);
4950 },
4951 });
4942 - expect(Scheduler).toFlushAndYield([]);
4952 + await waitForAll([]);
4953 expect(errors).toEqual([]);
4954 expect(getVisibleChildren(container)).toEqual(
4955 <div>
@@ -4985,7 +4995,7 @@ describe('ReactDOMFizzServer', () => {
4995 errors.push(error.message);
4996 },
4997 });
4988 - expect(Scheduler).toFlushAndYield([]);
4998 + await waitForAll([]);
4999 expect(errors).toEqual([]);
5000 expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
5001 });
@@ -5009,7 +5019,7 @@ describe('ReactDOMFizzServer', () => {
5019 errors.push(error.message);
5020 },
5021 });
5012 - expect(Scheduler).toFlushAndYield([]);
5022 + await waitForAll([]);
5023 expect(errors).toEqual([]);
5024 expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
5025 });
@@ -5044,7 +5054,7 @@ describe('ReactDOMFizzServer', () => {
5054 errors.push(error.message);
5055 },
5056 });
5047 - expect(Scheduler).toFlushAndYield([]);
5057 + await waitForAll([]);
5058 if (gate(flags => flags.enableFloat)) {
5059 expect(errors).toEqual([]);
5060 // with float, the title doesn't render on the client or on the server
@@ -5117,7 +5127,7 @@ describe('ReactDOMFizzServer', () => {
5127 errors.push(error.message);
5128 },
5129 });
5120 - expect(Scheduler).toFlushAndYield([]);
5130 + await waitForAll([]);
5131 expect(errors).toEqual([]);
5132 if (gate(flags => flags.enableFloat)) {
5133 // object titles are toStringed when float is on
@@ -5171,7 +5181,7 @@ describe('ReactDOMFizzServer', () => {
5181 expect(getVisibleChildren(container)).toEqual('ABC');
5182
5183 ReactDOMClient.hydrateRoot(container, <App />);
5174 - expect(Scheduler).toFlushAndYield([]);
5184 + await waitForAll([]);
5185 expect(getVisibleChildren(container)).toEqual('ABC');
5186 });
5187
@@ -5219,7 +5229,7 @@ describe('ReactDOMFizzServer', () => {
5229 ContextA._currentRenderer = null;
5230 ServerContext._currentRenderer = null;
5231 ReactDOMClient.hydrateRoot(container, <App />);
5222 - expect(Scheduler).toFlushAndYield([]);
5232 + await waitForAll([]);
5233 expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
5234 });
5235
@@ -5273,7 +5283,7 @@ describe('ReactDOMFizzServer', () => {
5283 expect(getVisibleChildren(container)).toEqual('ABCD');
5284
5285 ReactDOMClient.hydrateRoot(container, <App />);
5276 - expect(Scheduler).toFlushAndYield([]);
5286 + await waitForAll([]);
5287 expect(getVisibleChildren(container)).toEqual('ABCD');
5288 });
5289
@@ -5350,7 +5360,7 @@ describe('ReactDOMFizzServer', () => {
5360 reportedClientErrors.push(error);
5361 },
5362 });
5353 - expect(Scheduler).toFlushAndYield([]);
5363 + await waitForAll([]);
5364 expect(getVisibleChildren(container)).toEqual('Oops!');
5365 expect(reportedClientErrors.length).toBe(1);
5366 if (__DEV__) {
@@ -5383,7 +5393,7 @@ describe('ReactDOMFizzServer', () => {
5393 expect(getVisibleChildren(container)).toEqual('Hi');
5394
5395 ReactDOMClient.hydrateRoot(container, <App />);
5386 - expect(Scheduler).toFlushAndYield([]);
5396 + await waitForAll([]);
5397 expect(getVisibleChildren(container)).toEqual('Hi');
5398 });
5399
@@ -5437,7 +5447,7 @@ describe('ReactDOMFizzServer', () => {
5447 expect(getVisibleChildren(container)).toEqual(<button>0</button>);
5448
5449 ReactDOMClient.hydrateRoot(container, <App />);
5440 - expect(Scheduler).toFlushAndYield([]);
5450 + await waitForAll([]);
5451 expect(getVisibleChildren(container)).toEqual(<button>0</button>);
5452
5453 ref.current.dispatchEvent(
@@ -5502,8 +5512,8 @@ describe('ReactDOMFizzServer', () => {
5512 errors.push(error);
5513 },
5514 });
5505 - expect(() => {
5506 - expect(Scheduler).toFlushAndYield([]);
5515 + await expect(async () => {
5516 + await waitForAll([]);
5517 }).toErrorDev(
5518 [
5519 'Expected server HTML to contain a matching <span> in <div>',
packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js
+23 -19
@@ -22,6 +22,7 @@ let container;
22 let buffer = '';
23 let hasErrored = false;
24 let fatalError = undefined;
25 +let waitForAll;
26
27 describe('ReactDOMFizzServerHydrationWarning', () => {
28 beforeEach(() => {
@@ -33,6 +34,9 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
34 ReactDOMFizzServer = require('react-dom/server');
35 Stream = require('stream');
36
37 + const InternalTestUtils = require('internal-test-utils');
38 + waitForAll = InternalTestUtils.waitForAll;
39 +
40 // Test Environment
41 const jsdom = new JSDOM(
42 '<!DOCTYPE html><html><head></head><body><div id="container">',
@@ -155,7 +159,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
159 Scheduler.unstable_yieldValue(error.message);
160 },
161 });
158 - expect(Scheduler).toFlushAndYield([]);
162 + await waitForAll([]);
163 // The text mismatch should be *silently* fixed. Even in production.
164 expect(getVisibleChildren(container)).toEqual(
165 <div>
@@ -195,7 +199,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
199 Scheduler.unstable_yieldValue(error.message);
200 },
201 });
198 - expect(Scheduler).toFlushAndYield([]);
202 + await waitForAll([]);
203 expect(getVisibleChildren(container)).toEqual(
204 <div>
205 <span>
@@ -236,8 +240,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
240 Scheduler.unstable_yieldValue(error.message);
241 },
242 });
239 - expect(() => {
240 - expect(Scheduler).toFlushAndYield([
243 + await expect(async () => {
244 + await waitForAll([
245 'Hydration failed because the initial UI does not match what was rendered on the server.',
246 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
247 ]);
@@ -283,7 +287,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
287 Scheduler.unstable_yieldValue(error.message);
288 },
289 });
286 - expect(Scheduler).toFlushAndYield([]);
290 + await waitForAll([]);
291 expect(getVisibleChildren(container)).toEqual(
292 <div>
293 <span>{'Client'}</span>
@@ -319,8 +323,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
323 Scheduler.unstable_yieldValue(error.message);
324 },
325 });
322 - expect(() => {
323 - expect(Scheduler).toFlushAndYield([
326 + await expect(async () => {
327 + await waitForAll([
328 'Hydration failed because the initial UI does not match what was rendered on the server.',
329 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
330 ]);
@@ -367,8 +371,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
371 Scheduler.unstable_yieldValue(error.message);
372 },
373 });
370 - expect(() => {
371 - expect(Scheduler).toFlushAndYield([
374 + await expect(async () => {
375 + await waitForAll([
376 'Hydration failed because the initial UI does not match what was rendered on the server.',
377 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
378 ]);
@@ -418,8 +422,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
422 Scheduler.unstable_yieldValue(error.message);
423 },
424 });
421 - expect(() => {
422 - expect(Scheduler).toFlushAndYield([
425 + await expect(async () => {
426 + await waitForAll([
427 'Hydration failed because the initial UI does not match what was rendered on the server.',
428 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
429 ]);
@@ -467,8 +471,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
471 Scheduler.unstable_yieldValue(error.message);
472 },
473 });
470 - expect(() => {
471 - expect(Scheduler).toFlushAndYield([
474 + await expect(async () => {
475 + await waitForAll([
476 'Hydration failed because the initial UI does not match what was rendered on the server.',
477 'Hydration failed because the initial UI does not match what was rendered on the server.',
478 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
@@ -521,7 +525,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
525 Scheduler.unstable_yieldValue(error.message);
526 },
527 });
524 - expect(Scheduler).toFlushAndYield([]);
528 + await waitForAll([]);
529 expect(getVisibleChildren(container)).toEqual(
530 <div>
531 <span class="server" style="opacity:0" data-serveronly="server-only" />
@@ -558,7 +562,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
562 Scheduler.unstable_yieldValue(error.message);
563 },
564 });
561 - expect(Scheduler).toFlushAndYield([]);
565 + await waitForAll([]);
566 expect(getVisibleChildren(container)).toEqual(
567 <div>
568 <p>Server HTML</p>
@@ -591,8 +595,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
595 Scheduler.unstable_yieldValue(error.message);
596 },
597 });
594 - expect(() => {
595 - expect(Scheduler).toFlushAndYield([
598 + await expect(async () => {
599 + await waitForAll([
600 'Hydration failed because the initial UI does not match what was rendered on the server.',
601 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
602 ]);
@@ -637,8 +641,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
641 Scheduler.unstable_yieldValue(error.message);
642 },
643 });
640 - expect(() => {
641 - expect(Scheduler).toFlushAndYield([
644 + await expect(async () => {
645 + await waitForAll([
646 'Hydration failed because the initial UI does not match what was rendered on the server.',
647 'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
648 ]);
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+78 -68
@@ -33,6 +33,8 @@ let buffer = '';
33 let hasErrored = false;
34 let fatalError = undefined;
35 let renderOptions;
36 +let waitForAll;
37 +let assertLog;
38
39 function resetJSDOM(markup) {
40 // Test Environment
@@ -63,6 +65,10 @@ describe('ReactDOMFloat', () => {
65 Stream = require('stream');
66 Suspense = React.Suspense;
67
68 + const InternalTestUtils = require('internal-test-utils');
69 + waitForAll = InternalTestUtils.waitForAll;
70 + assertLog = InternalTestUtils.assertLog;
71 +
72 textCache = new Map();
73
74 resetJSDOM('<!DOCTYPE html><html><head></head><body><div id="container">');
@@ -259,10 +265,14 @@ describe('ReactDOMFloat', () => {
265 root.render(children);
266 return expect(() => {
267 try {
262 - expect(Scheduler).toFlushWithoutYielding();
268 + // TODO: Migrate this to waitForAll()
269 + Scheduler.unstable_flushAll();
270 + assertLog([]);
271 } catch (e) {
272 try {
265 - expect(Scheduler).toFlushWithoutYielding();
273 + // TODO: Migrate this to waitForAll()
274 + Scheduler.unstable_flushAll();
275 + assertLog([]);
276 } catch (f) {}
277 }
278 });
@@ -283,11 +293,11 @@ describe('ReactDOMFloat', () => {
293 </>,
294 );
295 try {
286 - expect(Scheduler).toFlushWithoutYielding();
296 + await waitForAll([]);
297 } catch (e) {
298 // for DOMExceptions that happen when expecting this test to fail we need
299 // to clear the scheduler first otherwise the expected failure will fail
290 - expect(Scheduler).toFlushWithoutYielding();
300 + await waitForAll([]);
301 throw e;
302 }
303 expect(getMeaningfulChildren(document)).toEqual(
@@ -351,7 +361,7 @@ describe('ReactDOMFloat', () => {
361 <body>foo</body>
362 </html>,
363 );
354 - expect(Scheduler).toFlushWithoutYielding();
364 + await waitForAll([]);
365 expect(getMeaningfulChildren(document)).toEqual(
366 <html>
367 <head>
@@ -476,7 +486,7 @@ describe('ReactDOMFloat', () => {
486 <script async={true} src="foo" />
487 </>,
488 );
479 - expect(Scheduler).toFlushWithoutYielding();
489 + await waitForAll([]);
490 expect(getMeaningfulChildren(document)).toEqual(
491 <html>
492 <head>
@@ -494,7 +504,7 @@ describe('ReactDOMFloat', () => {
504 <script data-new="new" async={true} src="foo" />
505 </>,
506 );
497 - expect(Scheduler).toFlushWithoutYielding();
507 + await waitForAll([]);
508 // we don't see the attribute because the resource is the same and was not reconstructed
509 expect(getMeaningfulChildren(document)).toEqual(
510 <html>
@@ -671,7 +681,7 @@ describe('ReactDOMFloat', () => {
681 </body>
682 </html>,
683 );
674 - expect(Scheduler).toFlushWithoutYielding();
684 + await waitForAll([]);
685 expect(getMeaningfulChildren(document)).toEqual(
686 <html>
687 <head>
@@ -968,7 +978,7 @@ body {
978 </body>
979 </html>,
980 );
971 - expect(Scheduler).toFlushWithoutYielding();
981 + await waitForAll([]);
982
983 expect(getMeaningfulChildren(document)).toEqual(
984 <html>
@@ -1107,7 +1117,7 @@ body {
1117 errors.push(err.digest);
1118 },
1119 });
1110 - expect(Scheduler).toFlushWithoutYielding();
1120 + await waitForAll([]);
1121 expect(getMeaningfulChildren(document)).toEqual(
1122 <html>
1123 <head>
@@ -1157,7 +1167,7 @@ body {
1167 <body>Hello</body>
1168 </html>,
1169 );
1160 - expect(Scheduler).toFlushWithoutYielding();
1170 + await waitForAll([]);
1171 expect(getMeaningfulChildren(document)).toEqual(
1172 <html>
1173 <head>
@@ -1627,7 +1637,7 @@ body {
1637 </body>
1638 </html>,
1639 );
1630 - expect(Scheduler).toFlushWithoutYielding();
1640 + await waitForAll([]);
1641 expect(getMeaningfulChildren(document)).toEqual(
1642 <html>
1643 <head>
@@ -1649,7 +1659,7 @@ body {
1659 </body>
1660 </html>,
1661 );
1652 - expect(Scheduler).toFlushWithoutYielding();
1662 + await waitForAll([]);
1663 expect(getMeaningfulChildren(document)).toEqual(
1664 <html>
1665 <head>
@@ -1694,7 +1704,7 @@ body {
1704 <Throw />
1705 </ErrorBoundary>,
1706 );
1697 - expect(Scheduler).toFlushWithoutYielding();
1707 + await waitForAll([]);
1708 expect(getMeaningfulChildren(document)).toEqual(
1709 <html>
1710 <head>
@@ -2327,8 +2337,8 @@ body {
2337 );
2338
2339 const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
2330 - expect(() => {
2331 - expect(Scheduler).toFlushWithoutYielding();
2340 + await expect(async () => {
2341 + await waitForAll([]);
2342 }).toErrorDev([
2343 'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
2344 'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
@@ -2343,8 +2353,8 @@ body {
2353 );
2354
2355 root.render(<App url="bar" />);
2346 - expect(() => {
2347 - expect(Scheduler).toFlushWithoutYielding();
2356 + await expect(async () => {
2357 + await waitForAll([]);
2358 }).toErrorDev([
2359 'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
2360 'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
@@ -2397,8 +2407,8 @@ body {
2407 );
2408
2409 const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
2400 - expect(() => {
2401 - expect(Scheduler).toFlushWithoutYielding();
2410 + await expect(async () => {
2411 + await waitForAll([]);
2412 }).toErrorDev(
2413 'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
2414 );
@@ -2414,8 +2424,8 @@ body {
2424 );
2425
2426 root.render(<App url="bar" />);
2417 - expect(() => {
2418 - expect(Scheduler).toFlushWithoutYielding();
2427 + await expect(async () => {
2428 + await waitForAll([]);
2429 }).toErrorDev(
2430 'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
2431 );
@@ -2502,7 +2512,7 @@ body {
2512 );
2513 }
2514 ReactDOMClient.hydrateRoot(document, <ClientApp />);
2505 - expect(Scheduler).toFlushWithoutYielding();
2515 + await waitForAll([]);
2516 expect(getMeaningfulChildren(document)).toEqual(
2517 <html>
2518 <head>
@@ -2724,7 +2734,7 @@ body {
2734 }
2735
2736 ReactDOMClient.hydrateRoot(document, <ClientApp />);
2727 - expect(Scheduler).toFlushWithoutYielding();
2737 + await waitForAll([]);
2738 expect(getMeaningfulChildren(document)).toEqual(
2739 <html>
2740 <head>
@@ -2754,7 +2764,7 @@ body {
2764
2765 const root = ReactDOMClient.createRoot(document);
2766 root.render(<App />);
2757 - expect(Scheduler).toFlushWithoutYielding();
2767 + await waitForAll([]);
2768 expect(getMeaningfulChildren(document)).toEqual(
2769 <html>
2770 <head>
@@ -2829,7 +2839,7 @@ body {
2839 }
2840
2841 ReactDOMClient.hydrateRoot(document, <ClientApp />);
2832 - expect(Scheduler).toFlushWithoutYielding();
2842 + await waitForAll([]);
2843 expect(getMeaningfulChildren(document)).toEqual(
2844 <html>
2845 <head>
@@ -2858,7 +2868,7 @@ body {
2868
2869 const root = ReactDOMClient.createRoot(document);
2870 root.render(<App />);
2861 - expect(Scheduler).toFlushWithoutYielding();
2871 + await waitForAll([]);
2872 expect(getMeaningfulChildren(document)).toEqual(
2873 <html>
2874 <head>
@@ -3050,7 +3060,7 @@ body {
3060 </body>
3061 </html>,
3062 );
3053 - expect(Scheduler).toFlushWithoutYielding();
3063 + await waitForAll([]);
3064
3065 expect(getMeaningfulChildren(document)).toEqual(
3066 <html>
@@ -3088,7 +3098,7 @@ body {
3098 </body>
3099 </html>,
3100 );
3091 - expect(Scheduler).toFlushWithoutYielding();
3101 + await waitForAll([]);
3102
3103 expect(getMeaningfulChildren(document)).toEqual(
3104 <html>
@@ -3171,7 +3181,7 @@ body {
3181 </body>
3182 </html>,
3183 );
3174 - expect(Scheduler).toFlushWithoutYielding();
3184 + await waitForAll([]);
3185 expect(getMeaningfulChildren(document)).toEqual(
3186 <html>
3187 <head>
@@ -3206,7 +3216,7 @@ body {
3216 </body>
3217 </html>,
3218 );
3209 - expect(Scheduler).toFlushWithoutYielding();
3219 + await waitForAll([]);
3220
3221 root.render(
3222 <html>
@@ -3214,7 +3224,7 @@ body {
3224 <body>hello world</body>
3225 </html>,
3226 );
3217 - expect(Scheduler).toFlushWithoutYielding();
3227 + await waitForAll([]);
3228 expect(getMeaningfulChildren(document)).toEqual(
3229 <html>
3230 <head>
@@ -3256,8 +3266,8 @@ body {
3266 },
3267 },
3268 );
3259 - expect(() => {
3260 - expect(Scheduler).toFlushWithoutYielding();
3269 + await expect(async () => {
3270 + await waitForAll([]);
3271 }).toErrorDev(
3272 [
3273 'Warning: Text content did not match. Server: "server" Client: "client"',
@@ -3308,8 +3318,8 @@ body {
3318 },
3319 },
3320 );
3311 - expect(() => {
3312 - expect(Scheduler).toFlushWithoutYielding();
3321 + await expect(async () => {
3322 + await waitForAll([]);
3323 }).toErrorDev(
3324 [
3325 'Warning: Text content did not match. Server: "server" Client: "client"',
@@ -3342,7 +3352,7 @@ body {
3352 </body>
3353 </html>,
3354 );
3345 - expect(Scheduler).toFlushWithoutYielding();
3355 + await waitForAll([]);
3356 expect(getMeaningfulChildren(document)).toEqual(
3357 <html>
3358 <head>
@@ -3364,7 +3374,7 @@ body {
3374 </body>
3375 </html>,
3376 );
3367 - expect(Scheduler).toFlushWithoutYielding();
3377 + await waitForAll([]);
3378 // The reason we do not see preloads in the head is they are inserted synchronously
3379 // during render and then when the new singleton mounts it resets it's content, retaining only styles
3380 expect(getMeaningfulChildren(document)).toEqual(
@@ -3401,7 +3411,7 @@ body {
3411 container
3412 </>,
3413 );
3404 - expect(Scheduler).toFlushWithoutYielding();
3414 + await waitForAll([]);
3415 expect(getMeaningfulChildren(document)).toEqual(
3416 <html>
3417 <head>
@@ -3461,7 +3471,7 @@ body {
3471 container
3472 </>,
3473 );
3464 - expect(Scheduler).toFlushWithoutYielding();
3474 + await waitForAll([]);
3475 expect(getMeaningfulChildren(document)).toEqual(
3476 <html>
3477 <head>
@@ -3533,7 +3543,7 @@ body {
3543 );
3544 }
3545 root.render(<ClientApp />);
3536 - expect(Scheduler).toFlushWithoutYielding();
3546 + await waitForAll([]);
3547 expect(getMeaningfulChildren(document)).toEqual(
3548 <html>
3549 <head>
@@ -3596,7 +3606,7 @@ body {
3606 container = document.getElementById('container');
3607 const root = ReactDOMClient.createRoot(container);
3608 root.render(<App />);
3599 - expect(Scheduler).toFlushWithoutYielding();
3609 + await waitForAll([]);
3610 expect(getMeaningfulChildren(document)).toEqual(
3611 <html>
3612 <head>
@@ -3672,7 +3682,7 @@ body {
3682 </svg>
3683 </div>,
3684 );
3675 - expect(Scheduler).toFlushWithoutYielding();
3685 + await waitForAll([]);
3686 expect(getMeaningfulChildren(document.body)).toEqual(
3687 <div>
3688 <svg>
@@ -3718,7 +3728,7 @@ body {
3728 </noscript>
3729 </div>,
3730 );
3721 - expect(Scheduler).toFlushWithoutYielding();
3731 + await waitForAll([]);
3732 expect(getMeaningfulChildren(document.body)).toEqual(
3733 <div>
3734 {/* On the client, <noscript> never renders children */}
@@ -3793,8 +3803,8 @@ body {
3803 </body>
3804 </html>,
3805 );
3796 - expect(() => {
3797 - expect(Scheduler).toFlushWithoutYielding();
3806 + await expect(async () => {
3807 + await waitForAll([]);
3808 }).toErrorDev([
3809 'React encountered a <link rel="stylesheet" href="foo" ... /> with a `precedence` prop that also included the `onLoad` and `onError` props. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.',
3810 ]);
@@ -4064,7 +4074,7 @@ background-color: green;
4074 </body>
4075 </html>,
4076 );
4067 - expect(Scheduler).toFlushWithoutYielding();
4077 + await waitForAll([]);
4078
4079 expect(getMeaningfulChildren(document)).toEqual(
4080 <html>
@@ -4095,7 +4105,7 @@ background-color: green;
4105 </body>
4106 </html>,
4107 );
4098 - expect(Scheduler).toFlushWithoutYielding();
4108 + await waitForAll([]);
4109 expect(getMeaningfulChildren(document)).toEqual(
4110 <html>
4111 <head>
@@ -4493,7 +4503,7 @@ background-color: green;
4503 </body>
4504 </html>,
4505 );
4496 - expect(Scheduler).toFlushWithoutYielding();
4506 + await waitForAll([]);
4507 // The async script with onLoad is inserted in the right place but does not cause the hydration
4508 // to fail.
4509 expect(getMeaningfulChildren(document)).toEqual(
@@ -4560,7 +4570,7 @@ background-color: green;
4570 </svg>
4571 </div>,
4572 );
4563 - expect(Scheduler).toFlushWithoutYielding();
4573 + await waitForAll([]);
4574 expect(getMeaningfulChildren(document.body)).toEqual(
4575 <div>
4576 <svg>
@@ -4606,7 +4616,7 @@ background-color: green;
4616 </noscript>
4617 </div>,
4618 );
4609 - expect(Scheduler).toFlushWithoutYielding();
4619 + await waitForAll([]);
4620 expect(getMeaningfulChildren(document.body)).toEqual(
4621 <div>
4622 {/* On the client, <noscript> never renders children */}
@@ -4708,7 +4718,7 @@ background-color: green;
4718 </body>
4719 </html>,
4720 );
4711 - expect(Scheduler).toFlushWithoutYielding();
4721 + await waitForAll([]);
4722 expect(getMeaningfulChildren(document)).toEqual(
4723 <html>
4724 <head>
@@ -4723,7 +4733,7 @@ background-color: green;
4733 <body />
4734 </html>,
4735 );
4726 - expect(Scheduler).toFlushWithoutYielding();
4736 + await waitForAll([]);
4737 expect(getMeaningfulChildren(document)).toEqual(
4738 <html>
4739 <head />
@@ -4742,7 +4752,7 @@ background-color: green;
4752 </div>,
4753 );
4754 });
4745 - expect(Scheduler).toFlushWithoutYielding();
4755 + await waitForAll([]);
4756
4757 expect(getMeaningfulChildren(document.head)).toEqual(
4758 <meta name="foo" data-foo="data" content="bar" />,
@@ -4750,7 +4760,7 @@ background-color: green;
4760 expect(getMeaningfulChildren(container)).toEqual(<div />);
4761
4762 root.render(<div />);
4753 - expect(Scheduler).toFlushWithoutYielding();
4763 + await waitForAll([]);
4764 expect(getMeaningfulChildren(document.head)).toEqual(undefined);
4765 });
4766
@@ -4784,7 +4794,7 @@ background-color: green;
4794 </body>
4795 </html>,
4796 );
4787 - expect(Scheduler).toFlushWithoutYielding();
4797 + await waitForAll([]);
4798 expect(getMeaningfulChildren(document)).toEqual(
4799 <html>
4800 <head>
@@ -4799,7 +4809,7 @@ background-color: green;
4809 <body />
4810 </html>,
4811 );
4802 - expect(Scheduler).toFlushWithoutYielding();
4812 + await waitForAll([]);
4813 expect(getMeaningfulChildren(document)).toEqual(
4814 <html>
4815 <head />
@@ -4818,7 +4828,7 @@ background-color: green;
4828 </div>,
4829 );
4830 });
4821 - expect(Scheduler).toFlushWithoutYielding();
4831 + await waitForAll([]);
4832
4833 expect(getMeaningfulChildren(document.head)).toEqual(
4834 <link rel="foo" data-foo="data" href="foo" />,
@@ -4826,7 +4836,7 @@ background-color: green;
4836 expect(getMeaningfulChildren(container)).toEqual(<div />);
4837
4838 root.render(<div />);
4829 - expect(Scheduler).toFlushWithoutYielding();
4839 + await waitForAll([]);
4840 expect(getMeaningfulChildren(document.head)).toEqual(undefined);
4841 });
4842
@@ -4860,7 +4870,7 @@ background-color: green;
4870 </body>
4871 </html>,
4872 );
4863 - expect(Scheduler).toFlushWithoutYielding();
4873 + await waitForAll([]);
4874 expect(getMeaningfulChildren(document)).toEqual(
4875 <html>
4876 <head>
@@ -4875,7 +4885,7 @@ background-color: green;
4885 <body />
4886 </html>,
4887 );
4878 - expect(Scheduler).toFlushWithoutYielding();
4888 + await waitForAll([]);
4889 expect(getMeaningfulChildren(document)).toEqual(
4890 <html>
4891 <head />
@@ -4894,7 +4904,7 @@ background-color: green;
4904 </div>,
4905 );
4906 });
4897 - expect(Scheduler).toFlushWithoutYielding();
4907 + await waitForAll([]);
4908
4909 expect(getMeaningfulChildren(document.head)).toEqual(
4910 <title data-foo="foo">a title</title>,
@@ -4902,7 +4912,7 @@ background-color: green;
4912 expect(getMeaningfulChildren(container)).toEqual(<div />);
4913
4914 root.render(<div />);
4905 - expect(Scheduler).toFlushWithoutYielding();
4915 + await waitForAll([]);
4916 expect(getMeaningfulChildren(document.head)).toEqual(undefined);
4917 });
4918
@@ -5031,7 +5041,7 @@ background-color: green;
5041 <meta name="after" />
5042 </>,
5043 );
5034 - expect(Scheduler).toFlushWithoutYielding();
5044 + await waitForAll([]);
5045 expect(getMeaningfulChildren(document)).toEqual(
5046 <html>
5047 <head>
@@ -5051,7 +5061,7 @@ background-color: green;
5061 {null}
5062 </>,
5063 );
5054 - expect(Scheduler).toFlushWithoutYielding();
5064 + await waitForAll([]);
5065 expect(getMeaningfulChildren(document)).toEqual(
5066 <html>
5067 <head />
@@ -5157,8 +5167,8 @@ background-color: green;
5167 },
5168 );
5169 try {
5160 - expect(() => {
5161 - expect(Scheduler).toFlushWithoutYielding();
5170 + await expect(async () => {
5171 + await waitForAll([]);
5172 }).toErrorDev(
5173 [
5174 'Warning: Text content did not match. Server: "server" Client: "client"',
@@ -5169,7 +5179,7 @@ background-color: green;
5179 } catch (e) {
5180 // When gates are false this test fails on a DOMException if you don't clear the scheduler after catching.
5181 // When gates are true this branch should not be hit
5172 - expect(Scheduler).toFlushWithoutYielding();
5182 + await waitForAll([]);
5183 throw e;
5184 }
5185 expect(getMeaningfulChildren(document)).toEqual(
packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js
+5 -2
@@ -13,6 +13,7 @@ let React;
13 let ReactNoop;
14 let Scheduler;
15 let JSXDEVRuntime;
16 +let waitForAll;
17
18 describe('ReactDeprecationWarnings', () => {
19 beforeEach(() => {
@@ -20,6 +21,8 @@ describe('ReactDeprecationWarnings', () => {
21 React = require('react');
22 ReactNoop = require('react-noop-renderer');
23 Scheduler = require('scheduler');
24 + const InternalTestUtils = require('internal-test-utils');
25 + waitForAll = InternalTestUtils.waitForAll;
26 if (__DEV__) {
27 JSXDEVRuntime = require('react/jsx-dev-runtime');
28 }
@@ -86,7 +89,7 @@ describe('ReactDeprecationWarnings', () => {
89 );
90 });
91
89 - it('should warn when owner and self are the same for string refs', () => {
92 + it('should warn when owner and self are the same for string refs', async () => {
93 class RefComponent extends React.Component {
94 render() {
95 return null;
@@ -102,7 +105,7 @@ describe('ReactDeprecationWarnings', () => {
105 }).toErrorDev([
106 'Component "Component" contains the string ref "refComponent". Support for string refs will be removed in a future major release.',
107 ]);
105 - expect(Scheduler).toFlushWithoutYielding();
108 + await waitForAll([]);
109 });
110
111 it('should warn when owner and self are different for string refs', () => {
packages/react/src/__tests__/ReactProfiler-test.internal.js
+53 -54
@@ -17,6 +17,9 @@ let Scheduler;
17 let ReactTestRenderer;
18 let act;
19 let AdvanceTime;
20 +let assertLog;
21 +let waitFor;
22 +let waitForAll;
23
24 function loadModules({
25 enableProfilerTimer = true,
@@ -49,6 +52,11 @@ function loadModules({
52 ReactTestRenderer = require('react-test-renderer');
53 }
54
55 + const InternalTestUtils = require('internal-test-utils');
56 + assertLog = InternalTestUtils.assertLog;
57 + waitFor = InternalTestUtils.waitFor;
58 + waitForAll = InternalTestUtils.waitForAll;
59 +
60 AdvanceTime = class extends React.Component {
61 static defaultProps = {
62 byAmount: 10,
@@ -188,7 +196,7 @@ describe(`onRender`, () => {
196 expect(callback).toHaveBeenCalledTimes(2);
197 });
198
191 - it('is not invoked until the commit phase', () => {
199 + it('is not invoked until the commit phase', async () => {
200 const callback = jest.fn();
201
202 const Yield = ({value}) => {
@@ -209,9 +217,9 @@ describe(`onRender`, () => {
217 });
218
219 // Times are logged until a render is committed.
212 - expect(Scheduler).toFlushAndYieldThrough(['first']);
220 + await waitFor(['first']);
221 expect(callback).toHaveBeenCalledTimes(0);
214 - expect(Scheduler).toFlushAndYield(['last']);
222 + await waitForAll(['last']);
223 expect(callback).toHaveBeenCalledTimes(1);
224 });
225
@@ -248,7 +256,7 @@ describe(`onRender`, () => {
256
257 // TODO: unstable_now is called by more places than just the profiler.
258 // Rewrite this test so it's less fragile.
251 - expect(Scheduler).toHaveYielded([
259 + assertLog([
260 'read current time',
261 'read current time',
262 'read current time',
@@ -669,7 +677,7 @@ describe(`onRender`, () => {
677 </React.Profiler>,
678 );
679 });
672 - expect(Scheduler).toHaveYielded(['false:false', 'true:false', 'true:true']);
680 + assertLog(['false:false', 'true:false', 'true:true']);
681
682 expect(onRender).toHaveBeenCalledTimes(3);
683 expect(onRender.mock.calls[0][1]).toBe('mount');
@@ -711,7 +719,7 @@ describe(`onRender`, () => {
719 </React.Profiler>,
720 );
721 });
714 - expect(Scheduler).toHaveYielded([false, true]);
722 + assertLog([false, true]);
723
724 // Verify that the nested update inside of the sync work is appropriately tagged.
725 expect(onRender).toHaveBeenCalledTimes(2);
@@ -720,7 +728,7 @@ describe(`onRender`, () => {
728 });
729
730 describe('with regard to interruptions', () => {
723 - it('should accumulate actual time after a scheduling interruptions', () => {
731 + it('should accumulate actual time after a scheduling interruptions', async () => {
732 const callback = jest.fn();
733
734 const Yield = ({renderTime}) => {
@@ -741,11 +749,11 @@ describe(`onRender`, () => {
749 {unstable_isConcurrent: true},
750 );
751 });
744 - expect(Scheduler).toFlushAndYieldThrough(['Yield:2']);
752 + await waitFor(['Yield:2']);
753 expect(callback).toHaveBeenCalledTimes(0);
754
755 // Resume render for remaining children.
748 - expect(Scheduler).toFlushAndYield(['Yield:3']);
756 + await waitForAll(['Yield:3']);
757
758 // Verify that logged times include both durations above.
759 expect(callback).toHaveBeenCalledTimes(1);
@@ -756,7 +764,7 @@ describe(`onRender`, () => {
764 expect(call[5]).toBe(10); // commit time
765 });
766
759 - it('should not include time between frames', () => {
767 + it('should not include time between frames', async () => {
768 const callback = jest.fn();
769
770 const Yield = ({renderTime}) => {
@@ -781,7 +789,7 @@ describe(`onRender`, () => {
789 {unstable_isConcurrent: true},
790 );
791 });
784 - expect(Scheduler).toFlushAndYieldThrough(['Yield:5']);
792 + await waitFor(['Yield:5']);
793 expect(callback).toHaveBeenCalledTimes(0);
794
795 // Simulate time moving forward while frame is paused.
@@ -789,7 +797,7 @@ describe(`onRender`, () => {
797
798 // Flush the remaining work,
799 // Which should take an additional 10ms of simulated time.
792 - expect(Scheduler).toFlushAndYield(['Yield:10', 'Yield:17']);
800 + await waitForAll(['Yield:10', 'Yield:17']);
801 expect(callback).toHaveBeenCalledTimes(2);
802
803 const [innerCall, outerCall] = callback.mock.calls;
@@ -808,7 +816,7 @@ describe(`onRender`, () => {
816 expect(outerCall[5]).toBe(87); // commit time
817 });
818
811 - it('should report the expected times when a high-pri update replaces a mount in-progress', () => {
819 + it('should report the expected times when a high-pri update replaces a mount in-progress', async () => {
820 const callback = jest.fn();
821
822 const Yield = ({renderTime}) => {
@@ -831,7 +839,7 @@ describe(`onRender`, () => {
839 {unstable_isConcurrent: true},
840 );
841 });
834 - expect(Scheduler).toFlushAndYieldThrough(['Yield:10']);
842 + await waitFor(['Yield:10']);
843 expect(callback).toHaveBeenCalledTimes(0);
844
845 // Simulate time moving forward while frame is paused.
@@ -846,7 +854,7 @@ describe(`onRender`, () => {
854 </React.Profiler>,
855 );
856 });
849 - expect(Scheduler).toHaveYielded(['Yield:5']);
857 + assertLog(['Yield:5']);
858
859 // The initial work was thrown away in this case,
860 // So the actual and base times should only include the final rendered tree times.
@@ -860,11 +868,11 @@ describe(`onRender`, () => {
868 callback.mockReset();
869
870 // Verify no more unexpected callbacks from low priority work
863 - expect(Scheduler).toFlushWithoutYielding();
871 + await waitForAll([]);
872 expect(callback).toHaveBeenCalledTimes(0);
873 });
874
867 - it('should report the expected times when a high-priority update replaces a low-priority update', () => {
875 + it('should report the expected times when a high-priority update replaces a low-priority update', async () => {
876 const callback = jest.fn();
877
878 const Yield = ({renderTime}) => {
@@ -885,7 +893,7 @@ describe(`onRender`, () => {
893
894 // Render everything initially.
895 // This should take 21 seconds of actual and base time.
888 - expect(Scheduler).toFlushAndYield(['Yield:6', 'Yield:15']);
896 + await waitForAll(['Yield:6', 'Yield:15']);
897 expect(callback).toHaveBeenCalledTimes(1);
898 let call = callback.mock.calls[0];
899 expect(call[2]).toBe(21); // actual time
@@ -908,14 +916,14 @@ describe(`onRender`, () => {
916 </React.Profiler>,
917 );
918 });
911 - expect(Scheduler).toFlushAndYieldThrough(['Yield:3']);
919 + await waitFor(['Yield:3']);
920 expect(callback).toHaveBeenCalledTimes(0);
921
922 // Simulate time moving forward while frame is paused.
923 Scheduler.unstable_advanceTime(100); // 59 -> 159
924
925 // Render another 5ms of simulated time.
918 - expect(Scheduler).toFlushAndYieldThrough(['Yield:5']);
926 + await waitFor(['Yield:5']);
927 expect(callback).toHaveBeenCalledTimes(0);
928
929 // Simulate time moving forward while frame is paused.
@@ -930,7 +938,7 @@ describe(`onRender`, () => {
938 </React.Profiler>,
939 );
940 });
933 - expect(Scheduler).toHaveYielded(['Yield:11']);
941 + assertLog(['Yield:11']);
942
943 // The actual time should include only the most recent render,
944 // Because this lets us avoid a lot of commit phase reset complexity.
@@ -943,11 +951,11 @@ describe(`onRender`, () => {
951 expect(call[5]).toBe(275); // commit time
952
953 // Verify no more unexpected callbacks from low priority work
946 - expect(Scheduler).toFlushAndYield([]);
954 + await waitForAll([]);
955 expect(callback).toHaveBeenCalledTimes(1);
956 });
957
950 - it('should report the expected times when a high-priority update interrupts a low-priority update', () => {
958 + it('should report the expected times when a high-priority update interrupts a low-priority update', async () => {
959 const callback = jest.fn();
960
961 const Yield = ({renderTime}) => {
@@ -994,7 +1002,7 @@ describe(`onRender`, () => {
1002 // Render everything initially.
1003 // This simulates a total of 14ms of actual render time.
1004 // The base render time is also 14ms for the initial render.
997 - expect(Scheduler).toFlushAndYield([
1005 + await waitForAll([
1006 'FirstComponent:1',
1007 'Yield:4',
1008 'SecondComponent:2',
@@ -1016,7 +1024,7 @@ describe(`onRender`, () => {
1024 React.startTransition(() => {
1025 first.setState({renderTime: 10});
1026 });
1019 - expect(Scheduler).toFlushAndYieldThrough(['FirstComponent:10']);
1027 + await waitFor(['FirstComponent:10']);
1028 expect(callback).toHaveBeenCalledTimes(0);
1029
1030 // Simulate time moving forward while frame is paused.
@@ -1025,7 +1033,7 @@ describe(`onRender`, () => {
1033 // Interrupt with higher priority work.
1034 // This simulates a total of 37ms of actual render time.
1035 renderer.unstable_flushSync(() => second.setState({renderTime: 30}));
1028 - expect(Scheduler).toHaveYielded(['SecondComponent:30', 'Yield:7']);
1036 + assertLog(['SecondComponent:30', 'Yield:7']);
1037
1038 // The actual time should include only the most recent render (37ms),
1039 // Because this greatly simplifies the commit phase logic.
@@ -1049,7 +1057,7 @@ describe(`onRender`, () => {
1057 // The tree contains 42ms of base render time at this point,
1058 // Reflecting the most recent (longer) render durations.
1059 // TODO: This actual time should decrease by 10ms once the scheduler supports resuming.
1052 - expect(Scheduler).toFlushAndYield(['FirstComponent:10', 'Yield:4']);
1060 + await waitForAll(['FirstComponent:10', 'Yield:4']);
1061 expect(callback).toHaveBeenCalledTimes(1);
1062 call = callback.mock.calls[0];
1063 expect(call[2]).toBe(14); // actual time
@@ -1207,7 +1215,7 @@ describe(`onRender`, () => {
1215 );
1216 });
1217
1210 - it('should reset the fiber stack correct after a "complete" phase error', () => {
1218 + it('should reset the fiber stack correct after a "complete" phase error', async () => {
1219 jest.resetModules();
1220
1221 loadModules({
@@ -1242,7 +1250,7 @@ describe(`onRender`, () => {
1250 <span>hi</span>
1251 </React.Profiler>,
1252 );
1245 - expect(Scheduler).toFlushWithoutYielding();
1253 + await waitForAll([]);
1254 });
1255 });
1256 });
@@ -2381,12 +2389,12 @@ describe(`onNestedUpdateScheduled`, () => {
2389 );
2390 });
2391
2384 - expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
2392 + assertLog(['Component:false', 'Component:true']);
2393 expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
2394 expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
2395 });
2396
2389 - it('is called when a function component schedules a batched update during a layout effect', () => {
2397 + it('is called when a function component schedules a batched update during a layout effect', async () => {
2398 function Component() {
2399 const [didMount, setDidMount] = React.useState(false);
2400 React.useLayoutEffect(() => {
@@ -2409,7 +2417,7 @@ describe(`onNestedUpdateScheduled`, () => {
2417 <Component />
2418 </React.Profiler>,
2419 );
2412 - expect(Scheduler).toFlushAndYield(['Component:false', 'Component:true']);
2420 + await waitForAll(['Component:false', 'Component:true']);
2421
2422 expect(onRender).toHaveBeenCalledTimes(2);
2423 expect(onRender.mock.calls[0][1]).toBe('mount');
@@ -2452,7 +2460,7 @@ describe(`onNestedUpdateScheduled`, () => {
2460 );
2461 });
2462
2455 - expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
2463 + assertLog(['Component:false', 'Component:true']);
2464 expect(onNestedUpdateScheduledOne).toHaveBeenCalledTimes(1);
2465 expect(onNestedUpdateScheduledOne.mock.calls[0][0]).toBe('one');
2466 expect(onNestedUpdateScheduledTwo).toHaveBeenCalledTimes(1);
@@ -2500,7 +2508,7 @@ describe(`onNestedUpdateScheduled`, () => {
2508 );
2509 });
2510
2503 - expect(Scheduler).toHaveYielded([
2511 + assertLog([
2512 'ComponentRootOne:false',
2513 'ComponentRootTwo',
2514 'ComponentRootOne:true',
@@ -2530,7 +2538,7 @@ describe(`onNestedUpdateScheduled`, () => {
2538 );
2539 });
2540
2533 - expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
2541 + assertLog(['Component:false', 'Component:true']);
2542 expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
2543 });
2544
@@ -2555,12 +2563,12 @@ describe(`onNestedUpdateScheduled`, () => {
2563 </React.Profiler>,
2564 );
2565 });
2558 - expect(Scheduler).toHaveYielded(['Component:false']);
2566 + assertLog(['Component:false']);
2567
2568 act(() => {
2569 updateFnRef.current();
2570 });
2563 - expect(Scheduler).toHaveYielded(['Component:true']);
2571 + assertLog(['Component:true']);
2572 expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
2573 });
2574
@@ -2586,7 +2594,7 @@ describe(`onNestedUpdateScheduled`, () => {
2594 );
2595 });
2596
2589 - expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
2597 + assertLog(['Component:false', 'Component:true']);
2598 expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
2599 });
2600
@@ -2617,10 +2625,7 @@ describe(`onNestedUpdateScheduled`, () => {
2625 );
2626 });
2627
2620 - expect(Scheduler).toHaveYielded([
2621 - 'Component:false:false',
2622 - 'Component:true:false',
2623 - ]);
2628 + assertLog(['Component:false:false', 'Component:true:false']);
2629 expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
2630 expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
2631
@@ -2634,10 +2639,7 @@ describe(`onNestedUpdateScheduled`, () => {
2639 );
2640 });
2641
2637 - expect(Scheduler).toHaveYielded([
2638 - 'Component:true:false',
2639 - 'Component:true:true',
2640 - ]);
2642 + assertLog(['Component:true:false', 'Component:true:true']);
2643 expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(2);
2644 expect(onNestedUpdateScheduled.mock.calls[1][0]).toBe('test');
2645 });
@@ -2669,7 +2671,7 @@ describe(`onNestedUpdateScheduled`, () => {
2671 );
2672 });
2673
2672 - expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
2674 + assertLog(['Component:false', 'Component:true']);
2675 expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
2676 expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
2677 });
@@ -2708,7 +2710,7 @@ describe(`onNestedUpdateScheduled`, () => {
2710 </React.Profiler>,
2711 );
2712 });
2711 - expect(Scheduler).toHaveYielded(['Component:false:false']);
2713 + assertLog(['Component:false:false']);
2714 expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
2715
2716 act(() => {
@@ -2721,10 +2723,7 @@ describe(`onNestedUpdateScheduled`, () => {
2723 );
2724 });
2725
2724 - expect(Scheduler).toHaveYielded([
2725 - 'Component:true:false',
2726 - 'Component:true:true',
2727 - ]);
2726 + assertLog(['Component:true:false', 'Component:true:true']);
2727 expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
2728 expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
2729 });
@@ -2755,12 +2754,12 @@ describe(`onNestedUpdateScheduled`, () => {
2754 </React.Profiler>,
2755 );
2756 });
2758 - expect(Scheduler).toHaveYielded(['Component:false']);
2757 + assertLog(['Component:false']);
2758
2759 act(() => {
2760 updateFnRef.current();
2761 });
2763 - expect(Scheduler).toHaveYielded(['Component:true']);
2762 + assertLog(['Component:true']);
2763 expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
2764 });
2765
packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js
+10 -4
@@ -17,6 +17,8 @@ describe('ReactProfiler DevTools integration', () => {
17 let Scheduler;
18 let AdvanceTime;
19 let hook;
20 + let waitForAll;
21 + let waitFor;
22
23 beforeEach(() => {
24 global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
@@ -34,6 +36,10 @@ describe('ReactProfiler DevTools integration', () => {
36 React = require('react');
37 ReactTestRenderer = require('react-test-renderer');
38
39 + const InternalTestUtils = require('internal-test-utils');
40 + waitForAll = InternalTestUtils.waitForAll;
41 + waitFor = InternalTestUtils.waitFor;
42 +
43 AdvanceTime = class extends React.Component {
44 static defaultProps = {
45 byAmount: 10,
@@ -138,7 +144,7 @@ describe('ReactProfiler DevTools integration', () => {
144 ).toBe(7);
145 });
146
141 - it('regression test: #17159', () => {
147 + it('regression test: #17159', async () => {
148 function Text({text}) {
149 Scheduler.unstable_yieldValue(text);
150 return text;
@@ -148,7 +154,7 @@ describe('ReactProfiler DevTools integration', () => {
154
155 // Commit something
156 root.update(<Text text="A" />);
151 - expect(Scheduler).toFlushAndYield(['A']);
157 + await waitForAll(['A']);
158 expect(root).toMatchRenderedOutput('A');
159
160 // Advance time by many seconds, larger than the default expiration time
@@ -160,9 +166,9 @@ describe('ReactProfiler DevTools integration', () => {
166 });
167
168 // Update B should not instantly expire.
163 - expect(Scheduler).toFlushAndYieldThrough([]);
169 + await waitFor([]);
170
165 - expect(Scheduler).toFlushAndYield(['B']);
171 + await waitForAll(['B']);
172 expect(root).toMatchRenderedOutput('B');
173 });
174 });
packages/react/src/__tests__/forwardRef-test.internal.js
+18 -14
@@ -14,6 +14,7 @@ describe('forwardRef', () => {
14 let ReactFeatureFlags;
15 let ReactNoop;
16 let Scheduler;
17 + let waitForAll;
18
19 beforeEach(() => {
20 jest.resetModules();
@@ -23,9 +24,12 @@ describe('forwardRef', () => {
24 React = require('react');
25 ReactNoop = require('react-noop-renderer');
26 Scheduler = require('scheduler');
27 +
28 + const InternalTestUtils = require('internal-test-utils');
29 + waitForAll = InternalTestUtils.waitForAll;
30 });
31
28 - it('should work without a ref to be forwarded', () => {
32 + it('should work without a ref to be forwarded', async () => {
33 class Child extends React.Component {
34 render() {
35 Scheduler.unstable_yieldValue(this.props.value);
@@ -42,10 +46,10 @@ describe('forwardRef', () => {
46 ));
47
48 ReactNoop.render(<RefForwardingComponent value={123} />);
45 - expect(Scheduler).toFlushAndYield([123]);
49 + await waitForAll([123]);
50 });
51
48 - it('should forward a ref for a single child', () => {
52 + it('should forward a ref for a single child', async () => {
53 class Child extends React.Component {
54 render() {
55 Scheduler.unstable_yieldValue(this.props.value);
@@ -64,11 +68,11 @@ describe('forwardRef', () => {
68 const ref = React.createRef();
69
70 ReactNoop.render(<RefForwardingComponent ref={ref} value={123} />);
67 - expect(Scheduler).toFlushAndYield([123]);
71 + await waitForAll([123]);
72 expect(ref.current instanceof Child).toBe(true);
73 });
74
71 - it('should forward a ref for multiple children', () => {
75 + it('should forward a ref for multiple children', async () => {
76 class Child extends React.Component {
77 render() {
78 Scheduler.unstable_yieldValue(this.props.value);
@@ -93,11 +97,11 @@ describe('forwardRef', () => {
97 <div />
98 </div>,
99 );
96 - expect(Scheduler).toFlushAndYield([123]);
100 + await waitForAll([123]);
101 expect(ref.current instanceof Child).toBe(true);
102 });
103
100 - it('should maintain child instance and ref through updates', () => {
104 + it('should maintain child instance and ref through updates', async () => {
105 class Child extends React.Component {
106 constructor(props) {
107 super(props);
@@ -125,16 +129,16 @@ describe('forwardRef', () => {
129 };
130
131 ReactNoop.render(<RefForwardingComponent ref={setRef} value={123} />);
128 - expect(Scheduler).toFlushAndYield([123]);
132 + await waitForAll([123]);
133 expect(ref instanceof Child).toBe(true);
134 expect(setRefCount).toBe(1);
135 ReactNoop.render(<RefForwardingComponent ref={setRef} value={456} />);
132 - expect(Scheduler).toFlushAndYield([456]);
136 + await waitForAll([456]);
137 expect(ref instanceof Child).toBe(true);
138 expect(setRefCount).toBe(1);
139 });
140
137 - it('should not break lifecycle error handling', () => {
141 + it('should not break lifecycle error handling', async () => {
142 class ErrorBoundary extends React.Component {
143 state = {error: null};
144 componentDidCatch(error) {
@@ -175,7 +179,7 @@ describe('forwardRef', () => {
179 <RefForwardingComponent ref={ref} />
180 </ErrorBoundary>,
181 );
178 - expect(Scheduler).toFlushAndYield([
182 + await waitForAll([
183 'ErrorBoundary.render: try',
184 'Wrapper',
185 'BadRender throw',
@@ -192,7 +196,7 @@ describe('forwardRef', () => {
196 expect(ref.current).toBe(null);
197 });
198
195 - it('should not re-run the render callback on a deep setState', () => {
199 + it('should not re-run the render callback on a deep setState', async () => {
200 let inst;
201
202 class Inner extends React.Component {
@@ -219,9 +223,9 @@ describe('forwardRef', () => {
223 }
224
225 ReactNoop.render(<App />);
222 - expect(Scheduler).toFlushAndYield(['App', 'Forward', 'Middle', 'Inner']);
226 + await waitForAll(['App', 'Forward', 'Middle', 'Inner']);
227
228 inst.setState({});
225 - expect(Scheduler).toFlushAndYield(['Inner']);
229 + await waitForAll(['Inner']);
230 });
231 });
packages/react/src/__tests__/forwardRef-test.js
+31 -29
@@ -13,17 +13,19 @@ describe('forwardRef', () => {
13 let PropTypes;
14 let React;
15 let ReactNoop;
16 - let Scheduler;
16 + let waitForAll;
17
18 beforeEach(() => {
19 jest.resetModules();
20 PropTypes = require('prop-types');
21 React = require('react');
22 ReactNoop = require('react-noop-renderer');
23 - Scheduler = require('scheduler');
23 +
24 + const InternalTestUtils = require('internal-test-utils');
25 + waitForAll = InternalTestUtils.waitForAll;
26 });
27
26 - it('should update refs when switching between children', () => {
28 + it('should update refs when switching between children', async () => {
29 function FunctionComponent({forwardedRef, setRefOnDiv}) {
30 return (
31 <section>
@@ -40,25 +42,25 @@ describe('forwardRef', () => {
42 const ref = React.createRef();
43
44 ReactNoop.render(<RefForwardingComponent ref={ref} setRefOnDiv={true} />);
43 - expect(Scheduler).toFlushWithoutYielding();
45 + await waitForAll([]);
46 expect(ref.current.type).toBe('div');
47
48 ReactNoop.render(<RefForwardingComponent ref={ref} setRefOnDiv={false} />);
47 - expect(Scheduler).toFlushWithoutYielding();
49 + await waitForAll([]);
50 expect(ref.current.type).toBe('span');
51 });
52
51 - it('should support rendering null', () => {
53 + it('should support rendering null', async () => {
54 const RefForwardingComponent = React.forwardRef((props, ref) => null);
55
56 const ref = React.createRef();
57
58 ReactNoop.render(<RefForwardingComponent ref={ref} />);
57 - expect(Scheduler).toFlushWithoutYielding();
59 + await waitForAll([]);
60 expect(ref.current).toBe(null);
61 });
62
61 - it('should support rendering null for multiple children', () => {
63 + it('should support rendering null for multiple children', async () => {
64 const RefForwardingComponent = React.forwardRef((props, ref) => null);
65
66 const ref = React.createRef();
@@ -70,11 +72,11 @@ describe('forwardRef', () => {
72 <div />
73 </div>,
74 );
73 - expect(Scheduler).toFlushWithoutYielding();
75 + await waitForAll([]);
76 expect(ref.current).toBe(null);
77 });
78
77 - it('should support propTypes and defaultProps', () => {
79 + it('should support propTypes and defaultProps', async () => {
80 function FunctionComponent({forwardedRef, optional, required}) {
81 return (
82 <div ref={forwardedRef}>
@@ -103,14 +105,14 @@ describe('forwardRef', () => {
105 ReactNoop.render(
106 <RefForwardingComponent ref={ref} optional="foo" required="bar" />,
107 );
106 - expect(Scheduler).toFlushWithoutYielding();
108 + await waitForAll([]);
109 expect(ref.current.children).toEqual([
110 {text: 'foo', hidden: false},
111 {text: 'bar', hidden: false},
112 ]);
113
114 ReactNoop.render(<RefForwardingComponent ref={ref} required="foo" />);
113 - expect(Scheduler).toFlushWithoutYielding();
115 + await waitForAll([]);
116 expect(ref.current.children).toEqual([
117 {text: 'default', hidden: false},
118 {text: 'foo', hidden: false},
@@ -344,7 +346,7 @@ describe('forwardRef', () => {
346 );
347 });
348
347 - it('should not bailout if forwardRef is not wrapped in memo', () => {
349 + it('should not bailout if forwardRef is not wrapped in memo', async () => {
350 const Component = props => <div {...props} />;
351
352 let renderCount = 0;
@@ -357,15 +359,15 @@ describe('forwardRef', () => {
359 const ref = React.createRef();
360
361 ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
360 - expect(Scheduler).toFlushWithoutYielding();
362 + await waitForAll([]);
363 expect(renderCount).toBe(1);
364
365 ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
364 - expect(Scheduler).toFlushWithoutYielding();
366 + await waitForAll([]);
367 expect(renderCount).toBe(2);
368 });
369
368 - it('should bailout if forwardRef is wrapped in memo', () => {
370 + it('should bailout if forwardRef is wrapped in memo', async () => {
371 const Component = props => <div ref={props.forwardedRef} />;
372
373 let renderCount = 0;
@@ -380,13 +382,13 @@ describe('forwardRef', () => {
382 const ref = React.createRef();
383
384 ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
383 - expect(Scheduler).toFlushWithoutYielding();
385 + await waitForAll([]);
386 expect(renderCount).toBe(1);
387
388 expect(ref.current.type).toBe('div');
389
390 ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
389 - expect(Scheduler).toFlushWithoutYielding();
391 + await waitForAll([]);
392 expect(renderCount).toBe(1);
393
394 const differentRef = React.createRef();
@@ -394,18 +396,18 @@ describe('forwardRef', () => {
396 ReactNoop.render(
397 <RefForwardingComponent ref={differentRef} optional="foo" />,
398 );
397 - expect(Scheduler).toFlushWithoutYielding();
399 + await waitForAll([]);
400 expect(renderCount).toBe(2);
401
402 expect(ref.current).toBe(null);
403 expect(differentRef.current.type).toBe('div');
404
405 ReactNoop.render(<RefForwardingComponent ref={ref} optional="bar" />);
404 - expect(Scheduler).toFlushWithoutYielding();
406 + await waitForAll([]);
407 expect(renderCount).toBe(3);
408 });
409
408 - it('should custom memo comparisons to compose', () => {
410 + it('should custom memo comparisons to compose', async () => {
411 const Component = props => <div ref={props.forwardedRef} />;
412
413 let renderCount = 0;
@@ -421,19 +423,19 @@ describe('forwardRef', () => {
423 const ref = React.createRef();
424
425 ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="0" c="1" />);
424 - expect(Scheduler).toFlushWithoutYielding();
426 + await waitForAll([]);
427 expect(renderCount).toBe(1);
428
429 expect(ref.current.type).toBe('div');
430
431 // Changing either a or b rerenders
432 ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="1" />);
431 - expect(Scheduler).toFlushWithoutYielding();
433 + await waitForAll([]);
434 expect(renderCount).toBe(2);
435
436 // Changing c doesn't rerender
437 ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="2" />);
436 - expect(Scheduler).toFlushWithoutYielding();
438 + await waitForAll([]);
439 expect(renderCount).toBe(2);
440
441 const ComposedMemo = React.memo(
@@ -442,29 +444,29 @@ describe('forwardRef', () => {
444 );
445
446 ReactNoop.render(<ComposedMemo ref={ref} a="0" b="0" c="0" />);
445 - expect(Scheduler).toFlushWithoutYielding();
447 + await waitForAll([]);
448 expect(renderCount).toBe(3);
449
450 // Changing just b no longer updates
451 ReactNoop.render(<ComposedMemo ref={ref} a="0" b="1" c="0" />);
450 - expect(Scheduler).toFlushWithoutYielding();
452 + await waitForAll([]);
453 expect(renderCount).toBe(3);
454
455 // Changing just a and c updates
456 ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="2" />);
455 - expect(Scheduler).toFlushWithoutYielding();
457 + await waitForAll([]);
458 expect(renderCount).toBe(4);
459
460 // Changing just c does not update
461 ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="3" />);
460 - expect(Scheduler).toFlushWithoutYielding();
462 + await waitForAll([]);
463 expect(renderCount).toBe(4);
464
465 // Changing ref still rerenders
466 const differentRef = React.createRef();
467
468 ReactNoop.render(<ComposedMemo ref={differentRef} a="2" b="2" c="3" />);
467 - expect(Scheduler).toFlushWithoutYielding();
469 + await waitForAll([]);
470 expect(renderCount).toBe(5);
471
472 expect(ref.current).toBe(null);
scripts/jest/config.build-devtools.js
+6
@@ -17,6 +17,12 @@ const packages = readdirSync(packagesRoot).filter(dir => {
17 if (dir.includes('react-devtools')) {
18 return false;
19 }
20 + if (dir === 'internal-test-utils') {
21 + // This is an internal package used only for testing. It's OK to read
22 + // from source.
23 + // TODO: Maybe let's have some convention for this?
24 + return false;
25 + }
26 const packagePath = join(packagesRoot, dir, 'package.json');
27 let stat;
28 try {