Codemod tests to waitFor pattern (1/?) (#26288)
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 2, 2023 at 22:34 UTC
25a8b9735ce7c84210707d5eced7fe2c9abbd0e1
15 files changed
+698
-905
packages/react-reconciler/src/__tests__/DebugTracing-test.internal.js
+5
-4
@@ -12,7 +12,7 @@
12
describe('DebugTracing', () => {
13
let React;
14
let ReactTestRenderer;
15
- let Scheduler;
15
+ let waitForPaint;
16
17
let logs;
18
@@ -27,7 +27,8 @@ describe('DebugTracing', () => {
27
28
React = require('react');
29
ReactTestRenderer = require('react-test-renderer');
30
- Scheduler = require('scheduler');
30
+ const InternalTestUtils = require('internal-test-utils');
31
+ waitForPaint = InternalTestUtils.waitForPaint;
32
33
logs = [];
34
@@ -100,7 +101,7 @@ describe('DebugTracing', () => {
101
});
102
103
// @gate experimental && build === 'development' && enableDebugTracing && enableCPUSuspense
103
- it('should log sync render with CPU suspense', () => {
104
+ it('should log sync render with CPU suspense', async () => {
105
function Example() {
106
console.log('<Example/>');
107
return null;
@@ -129,7 +130,7 @@ describe('DebugTracing', () => {
130
131
logs.splice(0);
132
132
- expect(Scheduler).toFlushUntilNextPaint([]);
133
+ await waitForPaint([]);
134
135
expect(logs).toEqual([
136
`group: ⚛️ render (${RETRY_LANE_STRING})`,
packages/react-reconciler/src/__tests__/ReactActWarnings-test.js
+37
-31
@@ -9,6 +9,8 @@
9
10
let React;
11
let Scheduler;
12
+let waitForAll;
13
+let assertLog;
14
let ReactNoop;
15
let useState;
16
let act;
@@ -32,6 +34,10 @@ describe('act warnings', () => {
34
startTransition = React.startTransition;
35
getCacheForType = React.unstable_getCacheForType;
36
caches = [];
37
+
38
+ const InternalTestUtils = require('internal-test-utils');
39
+ waitForAll = InternalTestUtils.waitForAll;
40
+ assertLog = InternalTestUtils.assertLog;
41
});
42
43
function createTextCache() {
@@ -134,17 +140,17 @@ describe('act warnings', () => {
140
}
141
}
142
137
- function withActEnvironment(value, scope) {
143
+ async function withActEnvironment(value, scope) {
144
const prevValue = global.IS_REACT_ACT_ENVIRONMENT;
145
global.IS_REACT_ACT_ENVIRONMENT = value;
146
try {
141
- return scope();
147
+ return await scope();
148
} finally {
149
global.IS_REACT_ACT_ENVIRONMENT = prevValue;
150
}
151
}
152
147
- test('warns about unwrapped updates only if environment flag is enabled', () => {
153
+ test('warns about unwrapped updates only if environment flag is enabled', async () => {
154
let setState;
155
function App() {
156
const [state, _setState] = useState(0);
@@ -154,34 +160,34 @@ describe('act warnings', () => {
160
161
const root = ReactNoop.createRoot();
162
root.render(<App />);
157
- expect(Scheduler).toFlushAndYield([0]);
163
+ await waitForAll([0]);
164
expect(root).toMatchRenderedOutput('0');
165
166
// Default behavior. Flag is undefined. No warning.
167
expect(global.IS_REACT_ACT_ENVIRONMENT).toBe(undefined);
168
setState(1);
163
- expect(Scheduler).toFlushAndYield([1]);
169
+ await waitForAll([1]);
170
expect(root).toMatchRenderedOutput('1');
171
172
// Flag is true. Warn.
167
- withActEnvironment(true, () => {
173
+ await withActEnvironment(true, async () => {
174
expect(() => setState(2)).toErrorDev(
175
'An update to App inside a test was not wrapped in act',
176
);
171
- expect(Scheduler).toFlushAndYield([2]);
177
+ await waitForAll([2]);
178
expect(root).toMatchRenderedOutput('2');
179
});
180
181
// Flag is false. No warning.
176
- withActEnvironment(false, () => {
182
+ await withActEnvironment(false, async () => {
183
setState(3);
178
- expect(Scheduler).toFlushAndYield([3]);
184
+ await waitForAll([3]);
185
expect(root).toMatchRenderedOutput('3');
186
});
187
});
188
189
// @gate __DEV__
184
- test('act warns if the environment flag is not enabled', () => {
190
+ test('act warns if the environment flag is not enabled', async () => {
191
let setState;
192
function App() {
193
const [state, _setState] = useState(0);
@@ -191,7 +197,7 @@ describe('act warnings', () => {
197
198
const root = ReactNoop.createRoot();
199
root.render(<App />);
194
- expect(Scheduler).toFlushAndYield([0]);
200
+ await waitForAll([0]);
201
expect(root).toMatchRenderedOutput('0');
202
203
// Default behavior. Flag is undefined. Warn.
@@ -204,20 +210,20 @@ describe('act warnings', () => {
210
'The current testing environment is not configured to support act(...)',
211
{withoutStack: true},
212
);
207
- expect(Scheduler).toHaveYielded([1]);
213
+ assertLog([1]);
214
expect(root).toMatchRenderedOutput('1');
215
216
// Flag is true. Don't warn.
211
- withActEnvironment(true, () => {
217
+ await withActEnvironment(true, () => {
218
act(() => {
219
setState(2);
220
});
215
- expect(Scheduler).toHaveYielded([2]);
221
+ assertLog([2]);
222
expect(root).toMatchRenderedOutput('2');
223
});
224
225
// Flag is false. Warn.
220
- withActEnvironment(false, () => {
226
+ await withActEnvironment(false, () => {
227
expect(() => {
228
act(() => {
229
setState(1);
@@ -226,13 +232,13 @@ describe('act warnings', () => {
232
'The current testing environment is not configured to support act(...)',
233
{withoutStack: true},
234
);
229
- expect(Scheduler).toHaveYielded([1]);
235
+ assertLog([1]);
236
expect(root).toMatchRenderedOutput('1');
237
});
238
});
239
234
- test('warns if root update is not wrapped', () => {
235
- withActEnvironment(true, () => {
240
+ test('warns if root update is not wrapped', async () => {
241
+ await withActEnvironment(true, () => {
242
const root = ReactNoop.createRoot();
243
expect(() => root.render('Hi')).toErrorDev(
244
// TODO: Better error message that doesn't make it look like "Root" is
@@ -244,7 +250,7 @@ describe('act warnings', () => {
250
});
251
252
// @gate __DEV__
247
- test('warns if class update is not wrapped', () => {
253
+ test('warns if class update is not wrapped', async () => {
254
let app;
255
class App extends React.Component {
256
state = {count: 0};
@@ -254,7 +260,7 @@ describe('act warnings', () => {
260
}
261
}
262
257
- withActEnvironment(true, () => {
263
+ await withActEnvironment(true, () => {
264
const root = ReactNoop.createRoot();
265
act(() => {
266
root.render(<App />);
@@ -266,7 +272,7 @@ describe('act warnings', () => {
272
});
273
274
// @gate __DEV__
269
- test('warns even if update is synchronous', () => {
275
+ test('warns even if update is synchronous', async () => {
276
let setState;
277
function App() {
278
const [state, _setState] = useState(0);
@@ -274,10 +280,10 @@ describe('act warnings', () => {
280
return <Text text={state} />;
281
}
282
277
- withActEnvironment(true, () => {
283
+ await withActEnvironment(true, () => {
284
const root = ReactNoop.createRoot();
285
act(() => root.render(<App />));
280
- expect(Scheduler).toHaveYielded([0]);
286
+ assertLog([0]);
287
expect(root).toMatchRenderedOutput('0');
288
289
// Even though this update is synchronous, we should still fire a warning,
@@ -286,14 +292,14 @@ describe('act warnings', () => {
292
'An update to App inside a test was not wrapped in act(...)',
293
);
294
289
- expect(Scheduler).toHaveYielded([1]);
295
+ assertLog([1]);
296
expect(root).toMatchRenderedOutput('1');
297
});
298
});
299
300
// @gate __DEV__
301
// @gate enableLegacyCache
296
- test('warns if Suspense retry is not wrapped', () => {
302
+ test('warns if Suspense retry is not wrapped', async () => {
303
function App() {
304
return (
305
<Suspense fallback={<Text text="Loading..." />}>
@@ -302,12 +308,12 @@ describe('act warnings', () => {
308
);
309
}
310
305
- withActEnvironment(true, () => {
311
+ await withActEnvironment(true, () => {
312
const root = ReactNoop.createRoot();
313
act(() => {
314
root.render(<App />);
315
});
310
- expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']);
316
+ assertLog(['Suspend! [Async]', 'Loading...']);
317
expect(root).toMatchRenderedOutput('Loading...');
318
319
// This is a retry, not a ping, because we already showed a fallback.
@@ -321,7 +327,7 @@ describe('act warnings', () => {
327
328
// @gate __DEV__
329
// @gate enableLegacyCache
324
- test('warns if Suspense ping is not wrapped', () => {
330
+ test('warns if Suspense ping is not wrapped', async () => {
331
function App({showMore}) {
332
return (
333
<Suspense fallback={<Text text="Loading..." />}>
@@ -330,12 +336,12 @@ describe('act warnings', () => {
336
);
337
}
338
333
- withActEnvironment(true, () => {
339
+ await withActEnvironment(true, () => {
340
const root = ReactNoop.createRoot();
341
act(() => {
342
root.render(<App showMore={false} />);
343
});
338
- expect(Scheduler).toHaveYielded(['(empty)']);
344
+ assertLog(['(empty)']);
345
expect(root).toMatchRenderedOutput('(empty)');
346
347
act(() => {
@@ -343,7 +349,7 @@ describe('act warnings', () => {
349
root.render(<App showMore={true} />);
350
});
351
});
346
- expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']);
352
+ assertLog(['Suspend! [Async]', 'Loading...']);
353
expect(root).toMatchRenderedOutput('(empty)');
354
355
// This is a ping, not a retry, because no fallback is showing.
packages/react-reconciler/src/__tests__/ReactBatching-test.internal.js
+19
-17
@@ -2,6 +2,8 @@ let React;
2
let ReactFeatureFlags;
3
let ReactNoop;
4
let Scheduler;
5
+let waitForAll;
6
+let assertLog;
7
let ReactCache;
8
let Suspense;
9
let TextResource;
@@ -18,6 +20,10 @@ describe('ReactBlockingMode', () => {
20
ReactCache = require('react-cache');
21
Suspense = React.Suspense;
22
23
+ const InternalTestUtils = require('internal-test-utils');
24
+ waitForAll = InternalTestUtils.waitForAll;
25
+ assertLog = InternalTestUtils.assertLog;
26
+
27
TextResource = ReactCache.unstable_createResource(
28
([text, ms = 0]) => {
29
return new Promise((resolve, reject) =>
@@ -52,7 +58,7 @@ describe('ReactBlockingMode', () => {
58
}
59
}
60
55
- it('updates flush without yielding in the next event', () => {
61
+ it('updates flush without yielding in the next event', async () => {
62
const root = ReactNoop.createRoot();
63
64
root.render(
@@ -66,12 +72,11 @@ describe('ReactBlockingMode', () => {
72
// Nothing should have rendered yet
73
expect(root).toMatchRenderedOutput(null);
74
69
- // Everything should render immediately in the next event
70
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
75
+ await waitForAll(['A', 'B', 'C']);
76
expect(root).toMatchRenderedOutput('ABC');
77
});
78
74
- it('layout updates flush synchronously in same event', () => {
79
+ it('layout updates flush synchronously in same event', async () => {
80
const {useLayoutEffect} = React;
81
82
function App() {
@@ -84,9 +89,9 @@ describe('ReactBlockingMode', () => {
89
const root = ReactNoop.createRoot();
90
root.render(<App />);
91
expect(root).toMatchRenderedOutput(null);
87
- expect(Scheduler).toHaveYielded([]);
92
+ assertLog([]);
93
89
- expect(Scheduler).toFlushAndYield(['Hi', 'Layout effect']);
94
+ await waitForAll(['Hi', 'Layout effect']);
95
expect(root).toMatchRenderedOutput('Hi');
96
});
97
@@ -106,15 +111,15 @@ describe('ReactBlockingMode', () => {
111
</Suspense>,
112
);
113
109
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'C', 'Loading...']);
114
+ await waitForAll(['A', 'Suspend! [B]', 'C', 'Loading...']);
115
// In Legacy Mode, A and B would mount in a hidden primary tree. In
116
// Concurrent Mode, nothing in the primary tree should mount. But the
117
// fallback should mount immediately.
118
expect(root).toMatchRenderedOutput('Loading...');
119
120
await jest.advanceTimersByTime(1000);
116
- expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
117
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
121
+ assertLog(['Promise resolved [B]']);
122
+ await waitForAll(['A', 'B', 'C']);
123
expect(root).toMatchRenderedOutput(
124
<>
125
<span>A</span>
@@ -124,7 +129,7 @@ describe('ReactBlockingMode', () => {
129
);
130
});
131
127
- it('flushSync does not flush batched work', () => {
132
+ it('flushSync does not flush batched work', async () => {
133
const {useState, forwardRef, useImperativeHandle} = React;
134
const root = ReactNoop.createRoot();
135
@@ -143,8 +148,7 @@ describe('ReactBlockingMode', () => {
148
</>,
149
);
150
146
- // Mount
147
- expect(Scheduler).toFlushAndYield(['A0', 'B0']);
151
+ await waitForAll(['A0', 'B0']);
152
expect(root).toMatchRenderedOutput('A0B0');
153
154
// Schedule a batched update to the first sibling
@@ -159,15 +163,13 @@ describe('ReactBlockingMode', () => {
163
164
// Now flush the first update
165
if (gate(flags => flags.enableUnifiedSyncLane)) {
162
- expect(Scheduler).toHaveYielded(['A1', 'B1']);
166
+ assertLog(['A1', 'B1']);
167
expect(root).toMatchRenderedOutput('A1B1');
168
} else {
165
- // Only the second update should have flushed synchronously
166
- expect(Scheduler).toHaveYielded(['B1']);
169
+ assertLog(['B1']);
170
expect(root).toMatchRenderedOutput('A0B1');
171
169
- // Now flush the first update
170
- expect(Scheduler).toFlushAndYield(['A1']);
172
+ await waitForAll(['A1']);
173
expect(root).toMatchRenderedOutput('A1B1');
174
}
175
});
packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js
+15
-19
@@ -10,6 +10,9 @@ let readText;
10
let resolveText;
11
// let rejectText;
12
13
+let assertLog;
14
+let waitForPaint;
15
+
16
describe('ReactSuspenseWithNoopRenderer', () => {
17
beforeEach(() => {
18
jest.resetModules();
@@ -21,6 +24,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
24
Suspense = React.Suspense;
25
useState = React.useState;
26
27
+ const InternalTestUtils = require('internal-test-utils');
28
+ assertLog = InternalTestUtils.assertLog;
29
+ waitForPaint = InternalTestUtils.waitForPaint;
30
+
31
textCache = new Map();
32
33
readText = text => {
@@ -128,7 +135,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
135
const root = ReactNoop.createRoot();
136
await act(async () => {
137
root.render(<App />);
131
- expect(Scheduler).toFlushUntilNextPaint(['Outer', 'Loading...']);
138
+ await waitForPaint(['Outer', 'Loading...']);
139
expect(root).toMatchRenderedOutput(
140
<>
141
Outer
@@ -136,8 +143,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
143
</>,
144
);
145
});
139
- // Inner contents finish in separate commit from outer
140
- expect(Scheduler).toHaveYielded(['Inner']);
146
+ assertLog(['Inner']);
147
expect(root).toMatchRenderedOutput(
148
<>
149
Outer
@@ -172,8 +178,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
178
await act(async () => {
179
root.render(<App />);
180
});
175
- // Inner contents finish in separate commit from outer
176
- expect(Scheduler).toHaveYielded(['Outer', 'Loading...', 'Inner [0]']);
181
+ assertLog(['Outer', 'Loading...', 'Inner [0]']);
182
expect(root).toMatchRenderedOutput(
183
<>
184
Outer
@@ -185,8 +190,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
190
await act(async () => {
191
setCount(1);
192
});
188
- // Entire update finishes in a single commit
189
- expect(Scheduler).toHaveYielded(['Outer', 'Inner [1]']);
193
+ assertLog(['Outer', 'Inner [1]']);
194
expect(root).toMatchRenderedOutput(
195
<>
196
Outer
@@ -215,7 +219,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
219
const root = ReactNoop.createRoot();
220
await act(async () => {
221
root.render(<App />);
218
- expect(Scheduler).toFlushUntilNextPaint(['Outer', 'Loading...']);
222
+ await waitForPaint(['Outer', 'Loading...']);
223
expect(root).toMatchRenderedOutput(
224
<>
225
Outer
@@ -223,8 +227,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
227
</>,
228
);
229
});
226
- // Inner contents suspended, so we continue showing a fallback.
227
- expect(Scheduler).toHaveYielded(['Suspend! [Inner]']);
230
+ assertLog(['Suspend! [Inner]']);
231
expect(root).toMatchRenderedOutput(
232
<>
233
Outer
@@ -236,7 +239,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
239
await act(async () => {
240
await resolveText('Inner');
241
});
239
- expect(Scheduler).toHaveYielded(['Inner']);
242
+ assertLog(['Inner']);
243
expect(root).toMatchRenderedOutput(
244
<>
245
Outer
@@ -273,14 +276,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
276
await act(async () => {
277
root.render(<App />);
278
});
276
- // Each level commits separately
277
- expect(Scheduler).toHaveYielded([
278
- 'A',
279
- 'Loading B...',
280
- 'B',
281
- 'Loading C...',
282
- 'C',
283
- ]);
279
+ assertLog(['A', 'Loading B...', 'B', 'Loading C...', 'C']);
280
expect(root).toMatchRenderedOutput(
281
<>
282
A
packages/react-reconciler/src/__tests__/ReactCache-test.js
+108
-170
@@ -3,6 +3,7 @@ let ReactNoop;
3
let Cache;
4
let getCacheSignal;
5
let Scheduler;
6
+let assertLog;
7
let act;
8
let Suspense;
9
let Offscreen;
@@ -32,6 +33,9 @@ describe('ReactCache', () => {
33
startTransition = React.startTransition;
34
useState = React.useState;
35
36
+ const InternalTestUtils = require('internal-test-utils');
37
+ assertLog = InternalTestUtils.assertLog;
38
+
39
textCaches = [];
40
seededCache = null;
41
@@ -203,20 +207,19 @@ describe('ReactCache', () => {
207
</Cache>,
208
);
209
});
206
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
210
+ assertLog(['Cache miss! [A]', 'Loading...']);
211
expect(root).toMatchRenderedOutput('Loading...');
212
213
await act(async () => {
214
resolveMostRecentTextCache('A');
215
});
212
- expect(Scheduler).toHaveYielded(['A']);
216
+ assertLog(['A']);
217
expect(root).toMatchRenderedOutput('A');
218
219
await act(async () => {
220
root.render('Bye');
221
});
218
- // no cleanup: cache is still retained at the root
219
- expect(Scheduler).toHaveYielded([]);
222
+ assertLog([]);
223
expect(root).toMatchRenderedOutput('Bye');
224
});
225
@@ -230,20 +233,19 @@ describe('ReactCache', () => {
233
</Suspense>,
234
);
235
});
233
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
236
+ assertLog(['Cache miss! [A]', 'Loading...']);
237
expect(root).toMatchRenderedOutput('Loading...');
238
239
await act(async () => {
240
resolveMostRecentTextCache('A');
241
});
239
- expect(Scheduler).toHaveYielded(['A']);
242
+ assertLog(['A']);
243
expect(root).toMatchRenderedOutput('A');
244
245
await act(async () => {
246
root.render('Bye');
247
});
245
- // no cleanup: cache is still retained at the root
246
- expect(Scheduler).toHaveYielded([]);
248
+ assertLog([]);
249
expect(root).toMatchRenderedOutput('Bye');
250
});
251
@@ -271,26 +273,19 @@ describe('ReactCache', () => {
273
root.render(<App showMore={false} />);
274
});
275
274
- // Even though there are two new <Cache /> trees, they should share the same
275
- // data cache. So there should be only a single cache miss for A.
276
- expect(Scheduler).toHaveYielded([
277
- 'Cache miss! [A]',
278
- 'Loading...',
279
- 'Loading...',
280
- ]);
276
+ assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
277
expect(root).toMatchRenderedOutput('Loading...Loading...');
278
279
await act(async () => {
280
resolveMostRecentTextCache('A');
281
});
286
- expect(Scheduler).toHaveYielded(['A', 'A']);
282
+ assertLog(['A', 'A']);
283
expect(root).toMatchRenderedOutput('AA');
284
285
await act(async () => {
286
root.render('Bye');
287
});
292
- // no cleanup: cache is still retained at the root
293
- expect(Scheduler).toHaveYielded([]);
288
+ assertLog([]);
289
expect(root).toMatchRenderedOutput('Bye');
290
});
291
@@ -319,34 +314,25 @@ describe('ReactCache', () => {
314
await act(async () => {
315
root.render(<App showMore={false} />);
316
});
322
- expect(Scheduler).toHaveYielded([]);
317
+ assertLog([]);
318
expect(root).toMatchRenderedOutput('(empty)');
319
320
await act(async () => {
321
root.render(<App showMore={true} />);
322
});
328
- // Even though there are two new <Cache /> trees, they should share the same
329
- // data cache. So there should be only a single cache miss for A.
330
- expect(Scheduler).toHaveYielded([
331
- 'Cache miss! [A]',
332
- 'Loading...',
333
- 'Loading...',
334
- ]);
323
+ assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
324
expect(root).toMatchRenderedOutput('Loading...Loading...');
325
326
await act(async () => {
327
resolveMostRecentTextCache('A');
328
});
340
- expect(Scheduler).toHaveYielded(['A', 'A']);
329
+ assertLog(['A', 'A']);
330
expect(root).toMatchRenderedOutput('AA');
331
332
await act(async () => {
333
root.render('Bye');
334
});
346
- // cleanup occurs for the cache shared by the inner cache boundaries (which
347
- // are not shared w the root because they were added in an update)
348
- // note that no cache is created for the root since the cache is never accessed
349
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v1]']);
335
+ assertLog(['Cache cleanup: A [v1]']);
336
expect(root).toMatchRenderedOutput('Bye');
337
});
338
@@ -370,22 +356,19 @@ describe('ReactCache', () => {
356
await act(async () => {
357
root.render(<App />);
358
});
373
- // Even though there is a nested <Cache /> boundary, it should share the same
374
- // data cache as the root. So there should be only a single cache miss for A.
375
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
359
+ assertLog(['Cache miss! [A]', 'Loading...']);
360
expect(root).toMatchRenderedOutput('Loading...');
361
362
await act(async () => {
363
resolveMostRecentTextCache('A');
364
});
381
- expect(Scheduler).toHaveYielded(['A', 'A']);
365
+ assertLog(['A', 'A']);
366
expect(root).toMatchRenderedOutput('AA');
367
368
await act(async () => {
369
root.render('Bye');
370
});
387
- // no cleanup: cache is still retained at the root
388
- expect(Scheduler).toHaveYielded([]);
371
+ assertLog([]);
372
expect(root).toMatchRenderedOutput('Bye');
373
},
374
);
@@ -412,14 +395,14 @@ describe('ReactCache', () => {
395
seedNextTextCache('A');
396
root.render(<App showMore={false} />);
397
});
415
- expect(Scheduler).toHaveYielded(['A [v1]']);
398
+ assertLog(['A [v1]']);
399
expect(root).toMatchRenderedOutput('A [v1]');
400
401
// Add a new cache boundary
402
await act(async () => {
403
root.render(<App showMore={true} />);
404
});
422
- expect(Scheduler).toHaveYielded([
405
+ assertLog([
406
'A [v1]',
407
// New tree should use already cached data
408
'A [v1]',
@@ -429,8 +412,7 @@ describe('ReactCache', () => {
412
await act(async () => {
413
root.render('Bye');
414
});
432
- // no cleanup: cache is still retained at the root
433
- expect(Scheduler).toHaveYielded([]);
415
+ assertLog([]);
416
expect(root).toMatchRenderedOutput('Bye');
417
});
418
@@ -460,14 +442,14 @@ describe('ReactCache', () => {
442
seedNextTextCache('A');
443
root.render(<App showMore={false} />);
444
});
463
- expect(Scheduler).toHaveYielded(['A [v1]']);
445
+ assertLog(['A [v1]']);
446
expect(root).toMatchRenderedOutput('A [v1]');
447
448
// Add a new cache boundary
449
await act(async () => {
450
root.render(<App showMore={true} />);
451
});
470
- expect(Scheduler).toHaveYielded([
452
+ assertLog([
453
'A [v1]',
454
// New tree should load fresh data.
455
'Cache miss! [A]',
@@ -477,7 +459,7 @@ describe('ReactCache', () => {
459
await act(async () => {
460
resolveMostRecentTextCache('A');
461
});
480
- expect(Scheduler).toHaveYielded(['A [v2]']);
462
+ assertLog(['A [v2]']);
463
expect(root).toMatchRenderedOutput('A [v1]A [v2]');
464
465
// Replace all the children: this should retain the root Cache instance,
@@ -486,9 +468,7 @@ describe('ReactCache', () => {
468
await act(async () => {
469
root.render('Bye!');
470
});
489
- // Cleanup occurs for the *second* cache instance: the first is still
490
- // referenced by the root
491
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v2]']);
471
+ assertLog(['Cache cleanup: A [v2]']);
472
expect(root).toMatchRenderedOutput('Bye!');
473
});
474
@@ -535,13 +515,13 @@ describe('ReactCache', () => {
515
await act(async () => {
516
root.render(<App />);
517
});
538
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading shell...']);
518
+ assertLog(['Cache miss! [A]', 'Loading shell...']);
519
expect(root).toMatchRenderedOutput('Loading shell...');
520
521
await act(async () => {
522
resolveMostRecentTextCache('A');
523
});
544
- expect(Scheduler).toHaveYielded([
524
+ assertLog([
525
'Shell',
526
// There's a cache miss for B, because it hasn't been read yet. But not
527
// A, because it was cached when we rendered the shell.
@@ -558,7 +538,7 @@ describe('ReactCache', () => {
538
await act(async () => {
539
resolveMostRecentTextCache('B');
540
});
561
- expect(Scheduler).toHaveYielded(['Content']);
541
+ assertLog(['Content']);
542
expect(root).toMatchRenderedOutput(
543
<>
544
<div>Shell</div>
@@ -569,8 +549,7 @@ describe('ReactCache', () => {
549
await act(async () => {
550
root.render('Bye');
551
});
572
- // no cleanup: cache is still retained at the root
573
- expect(Scheduler).toHaveYielded([]);
552
+ assertLog([]);
553
expect(root).toMatchRenderedOutput('Bye');
554
});
555
@@ -619,19 +598,19 @@ describe('ReactCache', () => {
598
await act(async () => {
599
root.render(<App showMore={false} />);
600
});
622
- expect(Scheduler).toHaveYielded([]);
601
+ assertLog([]);
602
expect(root).toMatchRenderedOutput('(empty)');
603
604
await act(async () => {
605
root.render(<App showMore={true} />);
606
});
628
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading shell...']);
607
+ assertLog(['Cache miss! [A]', 'Loading shell...']);
608
expect(root).toMatchRenderedOutput('Loading shell...');
609
610
await act(async () => {
611
resolveMostRecentTextCache('A');
612
});
634
- expect(Scheduler).toHaveYielded([
613
+ assertLog([
614
'Shell',
615
// There's a cache miss for B, because it hasn't been read yet. But not
616
// A, because it was cached when we rendered the shell.
@@ -648,7 +627,7 @@ describe('ReactCache', () => {
627
await act(async () => {
628
resolveMostRecentTextCache('B');
629
});
651
- expect(Scheduler).toHaveYielded(['Content']);
630
+ assertLog(['Content']);
631
expect(root).toMatchRenderedOutput(
632
<>
633
<div>Shell</div>
@@ -659,10 +638,7 @@ describe('ReactCache', () => {
638
await act(async () => {
639
root.render('Bye');
640
});
662
- expect(Scheduler).toHaveYielded([
663
- 'Cache cleanup: A [v1]',
664
- 'Cache cleanup: B [v1]',
665
- ]);
641
+ assertLog(['Cache cleanup: A [v1]', 'Cache cleanup: B [v1]']);
642
expect(root).toMatchRenderedOutput('Bye');
643
});
644
@@ -683,20 +659,20 @@ describe('ReactCache', () => {
659
</Suspense>,
660
);
661
});
686
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
662
+ assertLog(['Cache miss! [A]', 'Loading...']);
663
expect(root).toMatchRenderedOutput('Loading...');
664
665
await act(async () => {
666
resolveMostRecentTextCache('A');
667
});
692
- expect(Scheduler).toHaveYielded(['A [v1]']);
668
+ assertLog(['A [v1]']);
669
expect(root).toMatchRenderedOutput('A [v1]');
670
671
// Refresh for new data.
672
await act(async () => {
673
startTransition(() => refresh());
674
});
699
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
675
+ assertLog(['Cache miss! [A]', 'Loading...']);
676
expect(root).toMatchRenderedOutput('A [v1]');
677
678
await act(async () => {
@@ -704,9 +680,9 @@ describe('ReactCache', () => {
680
});
681
// Note that the version has updated
682
if (getCacheSignal) {
707
- expect(Scheduler).toHaveYielded(['A [v2]', 'Cache cleanup: A [v1]']);
683
+ assertLog(['A [v2]', 'Cache cleanup: A [v1]']);
684
} else {
709
- expect(Scheduler).toHaveYielded(['A [v2]']);
685
+ assertLog(['A [v2]']);
686
}
687
expect(root).toMatchRenderedOutput('A [v2]');
688
@@ -733,34 +709,32 @@ describe('ReactCache', () => {
709
</Suspense>,
710
);
711
});
736
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
712
+ assertLog(['Cache miss! [A]', 'Loading...']);
713
expect(root).toMatchRenderedOutput('Loading...');
714
715
await act(async () => {
716
resolveMostRecentTextCache('A');
717
});
742
- expect(Scheduler).toHaveYielded(['A [v1]']);
718
+ assertLog(['A [v1]']);
719
expect(root).toMatchRenderedOutput('A [v1]');
720
721
// Refresh for new data.
722
await act(async () => {
723
startTransition(() => refresh());
724
});
749
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
725
+ assertLog(['Cache miss! [A]', 'Loading...']);
726
expect(root).toMatchRenderedOutput('A [v1]');
727
728
await act(async () => {
729
resolveMostRecentTextCache('A');
730
});
755
- // Note that the version has updated, and the previous cache is cleared
756
- expect(Scheduler).toHaveYielded(['A [v2]', 'Cache cleanup: A [v1]']);
731
+ assertLog(['A [v2]', 'Cache cleanup: A [v1]']);
732
expect(root).toMatchRenderedOutput('A [v2]');
733
734
await act(async () => {
735
root.render('Bye');
736
});
762
- // the original root cache already cleaned up when the refresh completed
763
- expect(Scheduler).toHaveYielded([]);
737
+ assertLog([]);
738
expect(root).toMatchRenderedOutput('Bye');
739
});
740
@@ -781,20 +755,20 @@ describe('ReactCache', () => {
755
</Suspense>,
756
);
757
});
784
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
758
+ assertLog(['Cache miss! [A]', 'Loading...']);
759
expect(root).toMatchRenderedOutput('Loading...');
760
761
await act(async () => {
762
resolveMostRecentTextCache('A');
763
});
790
- expect(Scheduler).toHaveYielded(['A [v1]']);
764
+ assertLog(['A [v1]']);
765
expect(root).toMatchRenderedOutput('A [v1]');
766
767
// Refresh for new data.
768
await act(async () => {
769
refresh();
770
});
797
- expect(Scheduler).toHaveYielded([
771
+ assertLog([
772
'Cache miss! [A]',
773
'Loading...',
774
// The v1 cache can be cleaned up since everything that references it has
@@ -807,15 +781,13 @@ describe('ReactCache', () => {
781
await act(async () => {
782
resolveMostRecentTextCache('A');
783
});
810
- // Note that the version has updated, and the previous cache is cleared
811
- expect(Scheduler).toHaveYielded(['A [v2]']);
784
+ assertLog(['A [v2]']);
785
expect(root).toMatchRenderedOutput('A [v2]');
786
787
await act(async () => {
788
root.render('Bye');
789
});
817
- // the original root cache already cleaned up when the refresh completed
818
- expect(Scheduler).toHaveYielded([]);
790
+ assertLog([]);
791
expect(root).toMatchRenderedOutput('Bye');
792
});
793
@@ -847,13 +819,13 @@ describe('ReactCache', () => {
819
</Cache>,
820
);
821
});
850
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
822
+ assertLog(['Cache miss! [A]', 'Loading...']);
823
expect(root).toMatchRenderedOutput('Loading...');
824
825
await act(async () => {
826
resolveMostRecentTextCache('A');
827
});
856
- expect(Scheduler).toHaveYielded(['A [v1]']);
828
+ assertLog(['A [v1]']);
829
expect(root).toMatchRenderedOutput('A [v1]');
830
831
// Refresh for new data.
@@ -869,16 +841,13 @@ describe('ReactCache', () => {
841
}),
842
);
843
});
872
- // The root should re-render without a cache miss.
873
- // The cache is not cleared up yet, since it's still reference by the root
874
- expect(Scheduler).toHaveYielded(['A [v2]']);
844
+ assertLog(['A [v2]']);
845
expect(root).toMatchRenderedOutput('A [v2]');
846
847
await act(async () => {
848
root.render('Bye');
849
});
880
- // the refreshed cache boundary is unmounted and cleans up
881
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v2]']);
850
+ assertLog(['Cache cleanup: A [v2]']);
851
expect(root).toMatchRenderedOutput('Bye');
852
});
853
@@ -913,7 +882,7 @@ describe('ReactCache', () => {
882
seedNextTextCache('A');
883
root.render(<App showMore={false} />);
884
});
916
- expect(Scheduler).toHaveYielded(['A [v1]']);
885
+ assertLog(['A [v1]']);
886
expect(root).toMatchRenderedOutput('A [v1]');
887
888
// Add a new cache boundary
@@ -921,7 +890,7 @@ describe('ReactCache', () => {
890
seedNextTextCache('A');
891
root.render(<App showMore={true} />);
892
});
924
- expect(Scheduler).toHaveYielded([
893
+ assertLog([
894
'A [v1]',
895
// New tree should load fresh data.
896
'A [v2]',
@@ -933,17 +902,13 @@ describe('ReactCache', () => {
902
await act(async () => {
903
startTransition(() => refreshShell());
904
});
936
- expect(Scheduler).toHaveYielded([
937
- 'Cache miss! [A]',
938
- 'Loading...',
939
- 'Loading...',
940
- ]);
905
+ assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
906
expect(root).toMatchRenderedOutput('A [v1]A [v2]');
907
908
await act(async () => {
909
resolveMostRecentTextCache('A');
910
});
946
- expect(Scheduler).toHaveYielded([
911
+ assertLog([
912
'A [v3]',
913
'A [v3]',
914
// once the refresh completes the inner showMore boundary frees its previous
@@ -955,9 +920,7 @@ describe('ReactCache', () => {
920
await act(async () => {
921
root.render('Bye!');
922
});
958
- // Unmounting children releases the refreshed cache instance only; the root
959
- // still retains the original cache instance used for the first render
960
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v3]']);
923
+ assertLog(['Cache cleanup: A [v3]']);
924
expect(root).toMatchRenderedOutput('Bye!');
925
});
926
@@ -1004,19 +967,13 @@ describe('ReactCache', () => {
967
root.render(<App showMore={true} />);
968
});
969
1007
- // Even though there are two new <Cache /> trees, they should share the same
1008
- // data cache. So there should be only a single cache miss for A.
1009
- expect(Scheduler).toHaveYielded([
1010
- 'Cache miss! [A]',
1011
- 'Loading...',
1012
- 'Loading...',
1013
- ]);
970
+ assertLog(['Cache miss! [A]', 'Loading...', 'Loading...']);
971
expect(root).toMatchRenderedOutput('Loading...Loading...');
972
973
await act(async () => {
974
resolveMostRecentTextCache('A');
975
});
1019
- expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]']);
976
+ assertLog(['A [v1]', 'A [v1]']);
977
expect(root).toMatchRenderedOutput('A [v1]A [v1]');
978
979
// Refresh the first boundary. It should not refresh the second boundary,
@@ -1024,12 +981,12 @@ describe('ReactCache', () => {
981
await act(async () => {
982
await refreshFirstBoundary();
983
});
1027
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
984
+ assertLog(['Cache miss! [A]', 'Loading...']);
985
986
await act(async () => {
987
resolveMostRecentTextCache('A');
988
});
1032
- expect(Scheduler).toHaveYielded(['A [v2]']);
989
+ assertLog(['A [v2]']);
990
expect(root).toMatchRenderedOutput('A [v2]A [v1]');
991
992
// Unmount children: this should clear *both* cache instances:
@@ -1041,10 +998,7 @@ describe('ReactCache', () => {
998
await act(async () => {
999
root.render('Bye!');
1000
});
1044
- expect(Scheduler).toHaveYielded([
1045
- 'Cache cleanup: A [v2]',
1046
- 'Cache cleanup: A [v1]',
1047
- ]);
1001
+ assertLog(['Cache cleanup: A [v2]', 'Cache cleanup: A [v1]']);
1002
expect(root).toMatchRenderedOutput('Bye!');
1003
},
1004
);
@@ -1079,11 +1033,7 @@ describe('ReactCache', () => {
1033
await act(async () => {
1034
root.render(<App showMore={false} />);
1035
});
1082
- expect(Scheduler).toHaveYielded([
1083
- 'Cache miss! [A]',
1084
- 'Cache miss! [B]',
1085
- 'Loading...',
1086
- ]);
1036
+ assertLog(['Cache miss! [A]', 'Cache miss! [B]', 'Loading...']);
1037
expect(root).toMatchRenderedOutput('Loading...');
1038
1039
await act(async () => {
@@ -1093,7 +1043,7 @@ describe('ReactCache', () => {
1043
// And mount the second tree, which includes new content
1044
root.render(<App showMore={true} />);
1045
});
1096
- expect(Scheduler).toHaveYielded([
1046
+ assertLog([
1047
// The new tree should use a fresh cache
1048
'Cache miss! [A]',
1049
'Loading...',
@@ -1108,16 +1058,13 @@ describe('ReactCache', () => {
1058
await act(async () => {
1059
resolveMostRecentTextCache('A');
1060
});
1111
- expect(Scheduler).toHaveYielded(['A [v2]']);
1061
+ assertLog(['A [v2]']);
1062
expect(root).toMatchRenderedOutput('A [v2] A [v1] B [v1]');
1063
1064
await act(async () => {
1065
root.render('Bye!');
1066
});
1117
- // Unmounting children releases both cache boundaries, but the original
1118
- // cache instance (used by second boundary) is still referenced by the root.
1119
- // only the second cache instance is freed.
1120
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v2]']);
1067
+ assertLog(['Cache cleanup: A [v2]']);
1068
expect(root).toMatchRenderedOutput('Bye!');
1069
},
1070
);
@@ -1138,7 +1085,7 @@ describe('ReactCache', () => {
1085
<Suspense fallback={<Text text="Loading..." />}>(empty)</Suspense>,
1086
);
1087
});
1141
- expect(Scheduler).toHaveYielded([]);
1088
+ assertLog([]);
1089
expect(root).toMatchRenderedOutput('(empty)');
1090
1091
await act(async () => {
@@ -1150,7 +1097,7 @@ describe('ReactCache', () => {
1097
);
1098
});
1099
});
1153
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
1100
+ assertLog(['Cache miss! [A]', 'Loading...']);
1101
expect(root).toMatchRenderedOutput('(empty)');
1102
1103
await act(async () => {
@@ -1163,7 +1110,7 @@ describe('ReactCache', () => {
1110
);
1111
});
1112
});
1166
- expect(Scheduler).toHaveYielded([
1113
+ assertLog([
1114
// No cache miss, because it uses the pooled cache
1115
'Loading...',
1116
]);
@@ -1173,7 +1120,7 @@ describe('ReactCache', () => {
1120
await act(async () => {
1121
resolveMostRecentTextCache('A');
1122
});
1176
- expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]']);
1123
+ assertLog(['A [v1]', 'A [v1]']);
1124
expect(root).toMatchRenderedOutput('A [v1]A [v1]');
1125
1126
// Now do another transition
@@ -1188,7 +1135,7 @@ describe('ReactCache', () => {
1135
);
1136
});
1137
});
1191
- expect(Scheduler).toHaveYielded([
1138
+ assertLog([
1139
// First two children use the old cache because they already finished
1140
'A [v1]',
1141
'A [v1]',
@@ -1201,7 +1148,7 @@ describe('ReactCache', () => {
1148
await act(async () => {
1149
resolveMostRecentTextCache('A');
1150
});
1204
- expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]', 'A [v2]']);
1151
+ assertLog(['A [v1]', 'A [v1]', 'A [v2]']);
1152
expect(root).toMatchRenderedOutput('A [v1]A [v1]A [v2]');
1153
1154
// Unmount children: the first text cache instance is created only after the root
@@ -1211,10 +1158,7 @@ describe('ReactCache', () => {
1158
await act(async () => {
1159
root.render('Bye!');
1160
});
1214
- expect(Scheduler).toHaveYielded([
1215
- 'Cache cleanup: A [v1]',
1216
- 'Cache cleanup: A [v2]',
1217
- ]);
1161
+ assertLog(['Cache cleanup: A [v1]', 'Cache cleanup: A [v2]']);
1162
expect(root).toMatchRenderedOutput('Bye!');
1163
});
1164
@@ -1257,7 +1201,7 @@ describe('ReactCache', () => {
1201
await act(async () => {
1202
root.render(<App />);
1203
});
1260
- expect(Scheduler).toHaveYielded(['0']);
1204
+ assertLog(['0']);
1205
expect(root).toMatchRenderedOutput('0');
1206
1207
await act(async () => {
@@ -1265,13 +1209,13 @@ describe('ReactCache', () => {
1209
showMore();
1210
});
1211
});
1268
- expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']);
1212
+ assertLog(['Cache miss! [A]', 'Loading...']);
1213
expect(root).toMatchRenderedOutput('0');
1214
1215
await act(async () => {
1216
updateUnrelated(1);
1217
});
1274
- expect(Scheduler).toHaveYielded([
1218
+ assertLog([
1219
'1',
1220
1221
// Happens to re-render the fallback. Doesn't need to, but not relevant
@@ -1283,7 +1227,7 @@ describe('ReactCache', () => {
1227
await act(async () => {
1228
resolveMostRecentTextCache('A');
1229
});
1286
- expect(Scheduler).toHaveYielded(['A [v1]']);
1230
+ assertLog(['A [v1]']);
1231
expect(root).toMatchRenderedOutput('A [v1]1');
1232
1233
// Unmount children: the first text cache instance is created only after initial
@@ -1293,7 +1237,7 @@ describe('ReactCache', () => {
1237
await act(async () => {
1238
root.render('Bye!');
1239
});
1296
- expect(Scheduler).toHaveYielded(['Cache cleanup: A [v1]']);
1240
+ assertLog(['Cache cleanup: A [v1]']);
1241
expect(root).toMatchRenderedOutput('Bye!');
1242
});
1243
@@ -1310,7 +1254,7 @@ describe('ReactCache', () => {
1254
</Suspense>,
1255
);
1256
});
1313
- expect(Scheduler).toHaveYielded(['A [v1]']);
1257
+ assertLog(['A [v1]']);
1258
expect(root).toMatchRenderedOutput('A [v1]');
1259
1260
seedNextTextCache('B');
@@ -1323,7 +1267,7 @@ describe('ReactCache', () => {
1267
</Suspense>,
1268
);
1269
});
1326
- expect(Scheduler).toHaveYielded(['B [v2]']);
1270
+ assertLog(['B [v2]']);
1271
expect(root).toMatchRenderedOutput('B [v2]');
1272
1273
// Unmount children: the fresh cache instance for B cleans up since the cache boundary
@@ -1332,7 +1276,7 @@ describe('ReactCache', () => {
1276
await act(async () => {
1277
root.render('Bye!');
1278
});
1335
- expect(Scheduler).toHaveYielded(['Cache cleanup: B [v2]']);
1279
+ assertLog(['Cache cleanup: B [v2]']);
1280
expect(root).toMatchRenderedOutput('Bye!');
1281
});
1282
@@ -1348,13 +1292,13 @@ describe('ReactCache', () => {
1292
</Suspense>,
1293
);
1294
});
1351
- expect(Scheduler).toHaveYielded(['Cache miss! [A]']);
1295
+ assertLog(['Cache miss! [A]']);
1296
expect(root).toMatchRenderedOutput('Loading...');
1297
1298
await act(async () => {
1299
resolveMostRecentTextCache('A');
1300
});
1357
- expect(Scheduler).toHaveYielded(['A [v1]']);
1301
+ assertLog(['A [v1]']);
1302
expect(root).toMatchRenderedOutput('A [v1]');
1303
1304
// After a mount, subsequent transitions use a fresh cache
@@ -1369,7 +1313,7 @@ describe('ReactCache', () => {
1313
);
1314
});
1315
});
1372
- expect(Scheduler).toHaveYielded(['Cache miss! [B]']);
1316
+ assertLog(['Cache miss! [B]']);
1317
expect(root).toMatchRenderedOutput('A [v1]');
1318
1319
// Update to a different text and with a different key for the cache
@@ -1386,13 +1330,13 @@ describe('ReactCache', () => {
1330
);
1331
});
1332
});
1389
- expect(Scheduler).toHaveYielded(['Cache miss! [C]']);
1333
+ assertLog(['Cache miss! [C]']);
1334
expect(root).toMatchRenderedOutput('A [v1]');
1335
1336
await act(async () => {
1337
resolveMostRecentTextCache('C');
1338
});
1395
- expect(Scheduler).toHaveYielded(['C [v2]']);
1339
+ assertLog(['C [v2]']);
1340
expect(root).toMatchRenderedOutput('C [v2]');
1341
1342
// Unmount children: the fresh cache used for the updates is freed, while the
@@ -1400,10 +1344,7 @@ describe('ReactCache', () => {
1344
await act(async () => {
1345
root.render('Bye!');
1346
});
1403
- expect(Scheduler).toHaveYielded([
1404
- 'Cache cleanup: B [v2]',
1405
- 'Cache cleanup: C [v2]',
1406
- ]);
1347
+ assertLog(['Cache cleanup: B [v2]', 'Cache cleanup: C [v2]']);
1348
expect(root).toMatchRenderedOutput('Bye!');
1349
});
1350
@@ -1419,13 +1360,13 @@ describe('ReactCache', () => {
1360
</Suspense>,
1361
);
1362
});
1422
- expect(Scheduler).toHaveYielded(['Cache miss! [A]']);
1363
+ assertLog(['Cache miss! [A]']);
1364
expect(root).toMatchRenderedOutput('Loading...');
1365
1366
await act(async () => {
1367
resolveMostRecentTextCache('A');
1368
});
1428
- expect(Scheduler).toHaveYielded(['A [v1]']);
1369
+ assertLog(['A [v1]']);
1370
expect(root).toMatchRenderedOutput('A [v1]');
1371
1372
// After a mount, subsequent updates use a fresh cache
@@ -1438,7 +1379,7 @@ describe('ReactCache', () => {
1379
</Suspense>,
1380
);
1381
});
1441
- expect(Scheduler).toHaveYielded(['Cache miss! [B]']);
1382
+ assertLog(['Cache miss! [B]']);
1383
expect(root).toMatchRenderedOutput('Loading...');
1384
1385
// A second update uses the same fresh cache: even though this is a new
@@ -1452,13 +1393,13 @@ describe('ReactCache', () => {
1393
</Suspense>,
1394
);
1395
});
1455
- expect(Scheduler).toHaveYielded(['Cache miss! [C]']);
1396
+ assertLog(['Cache miss! [C]']);
1397
expect(root).toMatchRenderedOutput('Loading...');
1398
1399
await act(async () => {
1400
resolveMostRecentTextCache('C');
1401
});
1461
- expect(Scheduler).toHaveYielded(['C [v2]']);
1402
+ assertLog(['C [v2]']);
1403
expect(root).toMatchRenderedOutput('C [v2]');
1404
1405
// Unmount children: the fresh cache used for the updates is freed, while the
@@ -1466,10 +1407,7 @@ describe('ReactCache', () => {
1407
await act(async () => {
1408
root.render('Bye!');
1409
});
1469
- expect(Scheduler).toHaveYielded([
1470
- 'Cache cleanup: B [v2]',
1471
- 'Cache cleanup: C [v2]',
1472
- ]);
1410
+ assertLog(['Cache cleanup: B [v2]', 'Cache cleanup: C [v2]']);
1411
expect(root).toMatchRenderedOutput('Bye!');
1412
});
1413
@@ -1486,7 +1424,7 @@ describe('ReactCache', () => {
1424
</Suspense>,
1425
);
1426
});
1489
- expect(Scheduler).toHaveYielded(['A [v1]']);
1427
+ assertLog(['A [v1]']);
1428
expect(root).toMatchRenderedOutput('A [v1]');
1429
1430
// Start a transition from A -> B..., which should create a fresh cache
@@ -1502,7 +1440,7 @@ describe('ReactCache', () => {
1440
);
1441
});
1442
});
1505
- expect(Scheduler).toHaveYielded(['Cache miss! [B]']);
1443
+ assertLog(['Cache miss! [B]']);
1444
expect(root).toMatchRenderedOutput('A [v1]');
1445
1446
// ...but cancel by transitioning "back" to A (which we never really left)
@@ -1517,14 +1455,14 @@ describe('ReactCache', () => {
1455
);
1456
});
1457
});
1520
- expect(Scheduler).toHaveYielded(['A [v1]', 'Cache cleanup: B [v2]']);
1458
+ assertLog(['A [v1]', 'Cache cleanup: B [v2]']);
1459
expect(root).toMatchRenderedOutput('A [v1]');
1460
1461
// Unmount children: ...
1462
await act(async () => {
1463
root.render('Bye!');
1464
});
1527
- expect(Scheduler).toHaveYielded([]);
1465
+ assertLog([]);
1466
expect(root).toMatchRenderedOutput('Bye!');
1467
});
1468
@@ -1544,7 +1482,7 @@ describe('ReactCache', () => {
1482
</Suspense>,
1483
);
1484
});
1547
- expect(Scheduler).toHaveYielded(['A [v1]']);
1485
+ assertLog(['A [v1]']);
1486
expect(root).toMatchRenderedOutput('A [v1]');
1487
1488
await act(async () => {
@@ -1552,13 +1490,13 @@ describe('ReactCache', () => {
1490
refresh();
1491
});
1492
});
1555
- expect(Scheduler).toHaveYielded(['Cache miss! [A]']);
1493
+ assertLog(['Cache miss! [A]']);
1494
expect(root).toMatchRenderedOutput('A [v1]');
1495
1496
await act(async () => {
1497
root.render('Bye!');
1498
});
1561
- expect(Scheduler).toHaveYielded([
1499
+ assertLog([
1500
// TODO: the v1 cache should *not* be cleaned up, it is still retained by the root
1501
// The following line is presently yielded but should not be:
1502
// 'Cache cleanup: A [v1]',
@@ -1588,7 +1526,7 @@ describe('ReactCache', () => {
1526
</Suspense>,
1527
);
1528
});
1591
- expect(Scheduler).toHaveYielded(['A [v1]']);
1529
+ assertLog(['A [v1]']);
1530
expect(root).toMatchRenderedOutput('A [v1]');
1531
1532
await act(async () => {
@@ -1596,14 +1534,14 @@ describe('ReactCache', () => {
1534
refresh();
1535
});
1536
});
1599
- expect(Scheduler).toHaveYielded(['Cache miss! [A]']);
1537
+ assertLog(['Cache miss! [A]']);
1538
expect(root).toMatchRenderedOutput('A [v1]');
1539
1540
// Unmount the boundary before the refresh can complete
1541
await act(async () => {
1542
root.render('Bye!');
1543
});
1606
- expect(Scheduler).toHaveYielded([
1544
+ assertLog([
1545
// TODO: the v2 cache *should* be cleaned up, it was created for the abandoned refresh
1546
// The following line is presently not yielded but should be:
1547
'Cache cleanup: A [v2]',
@@ -1632,14 +1570,14 @@ describe('ReactCache', () => {
1570
await act(async () => {
1571
root.render(<App prerenderMore={false} />);
1572
});
1635
- expect(Scheduler).toHaveYielded([]);
1573
+ assertLog([]);
1574
expect(root).toMatchRenderedOutput(<div hidden={true} />);
1575
1576
seedNextTextCache('More');
1577
await act(async () => {
1578
root.render(<App prerenderMore={true} />);
1579
});
1642
- expect(Scheduler).toHaveYielded(['More']);
1580
+ assertLog(['More']);
1581
expect(root).toMatchRenderedOutput(<div hidden={true}>More</div>);
1582
});
1583
packages/react-reconciler/src/__tests__/ReactClassSetStateCallback-test.js
+6
-2
@@ -2,6 +2,7 @@ let React;
2
let ReactNoop;
3
let Scheduler;
4
let act;
5
+let assertLog;
6
7
describe('ReactClassSetStateCallback', () => {
8
beforeEach(() => {
@@ -11,6 +12,9 @@ describe('ReactClassSetStateCallback', () => {
12
ReactNoop = require('react-noop-renderer');
13
Scheduler = require('scheduler');
14
act = require('jest-react').act;
15
+
16
+ const InternalTestUtils = require('internal-test-utils');
17
+ assertLog = InternalTestUtils.assertLog;
18
});
19
20
function Text({text}) {
@@ -32,7 +36,7 @@ describe('ReactClassSetStateCallback', () => {
36
await act(async () => {
37
root.render(<App />);
38
});
35
- expect(Scheduler).toHaveYielded([0]);
39
+ assertLog([0]);
40
41
await act(async () => {
42
if (gate(flags => flags.enableUnifiedSyncLane)) {
@@ -52,6 +56,6 @@ describe('ReactClassSetStateCallback', () => {
56
);
57
});
58
});
55
- expect(Scheduler).toHaveYielded([2, 'Callback 2', 2, 'Callback 1']);
59
+ assertLog([2, 'Callback 2', 2, 'Callback 1']);
60
});
61
});
packages/react-reconciler/src/__tests__/ReactConcurrentErrorRecovery-test.js
+22
-57
@@ -5,6 +5,7 @@ let act;
5
let Suspense;
6
let getCacheForType;
7
let startTransition;
8
+let assertLog;
9
10
let caches;
11
let seededCache;
@@ -20,6 +21,9 @@ describe('ReactConcurrentErrorRecovery', () => {
21
Suspense = React.Suspense;
22
startTransition = React.startTransition;
23
24
+ const InternalTestUtils = require('internal-test-utils');
25
+ assertLog = InternalTestUtils.assertLog;
26
+
27
getCacheForType = React.unstable_getCacheForType;
28
29
caches = [];
@@ -196,7 +200,7 @@ describe('ReactConcurrentErrorRecovery', () => {
200
await act(async () => {
201
root.render(<App step={1} />);
202
});
199
- expect(Scheduler).toHaveYielded(['A1', 'B1']);
203
+ assertLog(['A1', 'B1']);
204
expect(root).toMatchRenderedOutput('A1B1');
205
206
// Start a refresh transition
@@ -205,12 +209,7 @@ describe('ReactConcurrentErrorRecovery', () => {
209
root.render(<App step={2} />);
210
});
211
});
208
- expect(Scheduler).toHaveYielded([
209
- 'Suspend! [A2]',
210
- 'Loading...',
211
- 'Suspend! [B2]',
212
- 'Loading...',
213
- ]);
212
+ assertLog(['Suspend! [A2]', 'Loading...', 'Suspend! [B2]', 'Loading...']);
213
// Because this is a refresh, we don't switch to a fallback
214
expect(root).toMatchRenderedOutput('A1B1');
215
@@ -222,7 +221,7 @@ describe('ReactConcurrentErrorRecovery', () => {
221
// Because we're still suspended on A, we can't show an error boundary. We
222
// should wait for A to resolve.
223
if (gate(flags => flags.replayFailedUnitOfWorkWithInvokeGuardedCallback)) {
225
- expect(Scheduler).toHaveYielded([
224
+ assertLog([
225
'Suspend! [A2]',
226
'Loading...',
227
@@ -233,12 +232,7 @@ describe('ReactConcurrentErrorRecovery', () => {
232
'Oops!',
233
]);
234
} else {
236
- expect(Scheduler).toHaveYielded([
237
- 'Suspend! [A2]',
238
- 'Loading...',
239
- 'Error! [B2]',
240
- 'Oops!',
241
- ]);
235
+ assertLog(['Suspend! [A2]', 'Loading...', 'Error! [B2]', 'Oops!']);
236
}
237
// Remain on previous screen.
238
expect(root).toMatchRenderedOutput('A1B1');
@@ -248,7 +242,7 @@ describe('ReactConcurrentErrorRecovery', () => {
242
resolveText('A2');
243
});
244
if (gate(flags => flags.replayFailedUnitOfWorkWithInvokeGuardedCallback)) {
251
- expect(Scheduler).toHaveYielded([
245
+ assertLog([
246
'A2',
247
'Error! [B2]',
248
// This extra log happens when we replay the error
@@ -264,15 +258,7 @@ describe('ReactConcurrentErrorRecovery', () => {
258
'Oops!',
259
]);
260
} else {
267
- expect(Scheduler).toHaveYielded([
268
- 'A2',
269
- 'Error! [B2]',
270
- 'Oops!',
271
-
272
- 'A2',
273
- 'Error! [B2]',
274
- 'Oops!',
275
- ]);
261
+ assertLog(['A2', 'Error! [B2]', 'Oops!', 'A2', 'Error! [B2]', 'Oops!']);
262
}
263
// Now we can show the error boundary that's wrapped around B.
264
expect(root).toMatchRenderedOutput('A2Oops!');
@@ -317,7 +303,7 @@ describe('ReactConcurrentErrorRecovery', () => {
303
await act(async () => {
304
root.render(<App step={1} />);
305
});
320
- expect(Scheduler).toHaveYielded(['A1', 'B1']);
306
+ assertLog(['A1', 'B1']);
307
expect(root).toMatchRenderedOutput('A1B1');
308
309
// Start a refresh transition
@@ -326,12 +312,7 @@ describe('ReactConcurrentErrorRecovery', () => {
312
root.render(<App step={2} />);
313
});
314
});
329
- expect(Scheduler).toHaveYielded([
330
- 'Suspend! [A2]',
331
- 'Loading...',
332
- 'Suspend! [B2]',
333
- 'Loading...',
334
- ]);
315
+ assertLog(['Suspend! [A2]', 'Loading...', 'Suspend! [B2]', 'Loading...']);
316
// Because this is a refresh, we don't switch to a fallback
317
expect(root).toMatchRenderedOutput('A1B1');
318
@@ -343,7 +324,7 @@ describe('ReactConcurrentErrorRecovery', () => {
324
// Because we're still suspended on B, we can't show an error boundary. We
325
// should wait for B to resolve.
326
if (gate(flags => flags.replayFailedUnitOfWorkWithInvokeGuardedCallback)) {
346
- expect(Scheduler).toHaveYielded([
327
+ assertLog([
328
'Error! [A2]',
329
// This extra log happens when we replay the error
330
// in invokeGuardedCallback
@@ -354,12 +335,7 @@ describe('ReactConcurrentErrorRecovery', () => {
335
'Loading...',
336
]);
337
} else {
357
- expect(Scheduler).toHaveYielded([
358
- 'Error! [A2]',
359
- 'Oops!',
360
- 'Suspend! [B2]',
361
- 'Loading...',
362
- ]);
338
+ assertLog(['Error! [A2]', 'Oops!', 'Suspend! [B2]', 'Loading...']);
339
}
340
// Remain on previous screen.
341
expect(root).toMatchRenderedOutput('A1B1');
@@ -369,7 +345,7 @@ describe('ReactConcurrentErrorRecovery', () => {
345
resolveText('B2');
346
});
347
if (gate(flags => flags.replayFailedUnitOfWorkWithInvokeGuardedCallback)) {
372
- expect(Scheduler).toHaveYielded([
348
+ assertLog([
349
'Error! [A2]',
350
// This extra log happens when we replay the error
351
// in invokeGuardedCallback
@@ -385,15 +361,7 @@ describe('ReactConcurrentErrorRecovery', () => {
361
'B2',
362
]);
363
} else {
388
- expect(Scheduler).toHaveYielded([
389
- 'Error! [A2]',
390
- 'Oops!',
391
- 'B2',
392
-
393
- 'Error! [A2]',
394
- 'Oops!',
395
- 'B2',
396
- ]);
364
+ assertLog(['Error! [A2]', 'Oops!', 'B2', 'Error! [A2]', 'Oops!', 'B2']);
365
}
366
// Now we can show the error boundary that's wrapped around B.
367
expect(root).toMatchRenderedOutput('Oops!B2');
@@ -422,7 +390,7 @@ describe('ReactConcurrentErrorRecovery', () => {
390
root.render(<AsyncText text="Async" />);
391
});
392
});
425
- expect(Scheduler).toHaveYielded(['Suspend! [Async]']);
393
+ assertLog(['Suspend! [Async]']);
394
expect(root).toMatchRenderedOutput(null);
395
396
// This also works if the suspended component is wrapped with an error
@@ -438,14 +406,14 @@ describe('ReactConcurrentErrorRecovery', () => {
406
);
407
});
408
});
441
- expect(Scheduler).toHaveYielded(['Suspend! [Async]']);
409
+ assertLog(['Suspend! [Async]']);
410
expect(root).toMatchRenderedOutput(null);
411
412
// Continues rendering once data resolves
413
await act(async () => {
414
resolveText('Async');
415
});
448
- expect(Scheduler).toHaveYielded(['Async']);
416
+ assertLog(['Async']);
417
expect(root).toMatchRenderedOutput('Async');
418
});
419
@@ -489,7 +457,7 @@ describe('ReactConcurrentErrorRecovery', () => {
457
);
458
});
459
});
492
- expect(Scheduler).toHaveYielded([
460
+ assertLog([
461
'Suspend! [Async]',
462
// TODO: Ideally we would skip this second render pass to render the
463
// error UI, since it's not going to commit anyway. The same goes for
@@ -510,17 +478,14 @@ describe('ReactConcurrentErrorRecovery', () => {
478
);
479
});
480
});
513
- expect(Scheduler).toHaveYielded([
514
- 'Suspend! [Async]',
515
- 'Caught an error: Oops!',
516
- ]);
481
+ assertLog(['Suspend! [Async]', 'Caught an error: Oops!']);
482
expect(root).toMatchRenderedOutput(null);
483
484
await act(async () => {
485
await resolveText('Async');
486
});
487
523
- expect(Scheduler).toHaveYielded([
488
+ assertLog([
489
'Async',
490
'Caught an error: Oops!',
491
packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js
+36
-37
@@ -9,6 +9,7 @@ let SuspenseList;
9
let getCacheForType;
10
let caches;
11
let seededCache;
12
+let assertLog;
13
14
describe('ReactLazyContextPropagation', () => {
15
beforeEach(() => {
@@ -25,6 +26,9 @@ describe('ReactLazyContextPropagation', () => {
26
SuspenseList = React.SuspenseList;
27
}
28
29
+ const InternalTestUtils = require('internal-test-utils');
30
+ assertLog = InternalTestUtils.assertLog;
31
+
32
getCacheForType = React.unstable_getCacheForType;
33
34
caches = [];
@@ -202,13 +206,13 @@ describe('ReactLazyContextPropagation', () => {
206
await act(async () => {
207
root.render(<App />);
208
});
205
- expect(Scheduler).toHaveYielded([0]);
209
+ assertLog([0]);
210
expect(root).toMatchRenderedOutput('0');
211
212
await act(async () => {
213
setValue(1);
214
});
211
- expect(Scheduler).toHaveYielded([1]);
215
+ assertLog([1]);
216
expect(root).toMatchRenderedOutput('1');
217
},
218
);
@@ -244,13 +248,13 @@ describe('ReactLazyContextPropagation', () => {
248
await act(async () => {
249
root.render(<App />);
250
});
247
- expect(Scheduler).toHaveYielded([0]);
251
+ assertLog([0]);
252
expect(root).toMatchRenderedOutput('0');
253
254
await act(async () => {
255
setValue(1);
256
});
253
- expect(Scheduler).toHaveYielded([1]);
257
+ assertLog([1]);
258
expect(root).toMatchRenderedOutput('1');
259
});
260
@@ -287,13 +291,13 @@ describe('ReactLazyContextPropagation', () => {
291
await act(async () => {
292
root.render(<App />);
293
});
290
- expect(Scheduler).toHaveYielded([0]);
294
+ assertLog([0]);
295
expect(root).toMatchRenderedOutput('0');
296
297
await act(async () => {
298
setValue(1);
299
});
296
- expect(Scheduler).toHaveYielded([1]);
300
+ assertLog([1]);
301
expect(root).toMatchRenderedOutput('1');
302
});
303
@@ -325,7 +329,7 @@ describe('ReactLazyContextPropagation', () => {
329
await act(async () => {
330
root.render(<App />);
331
});
328
- expect(Scheduler).toHaveYielded(['Consumer', 0]);
332
+ assertLog(['Consumer', 0]);
333
expect(root).toMatchRenderedOutput('0');
334
335
await act(async () => {
@@ -335,12 +339,7 @@ describe('ReactLazyContextPropagation', () => {
339
setOtherValue(1);
340
setOtherValue(0);
341
});
338
- // NOTE: If this didn't yield anything, that indicates that we never visited
339
- // the consumer during the render phase, which probably means the eager
340
- // bailout mechanism kicked in. Because we're testing the _lazy_ bailout
341
- // mechanism, update this test to foil the _eager_ bailout, somehow. Perhaps
342
- // by switching to useReducer.
343
- expect(Scheduler).toHaveYielded(['Consumer']);
342
+ assertLog(['Consumer']);
343
expect(root).toMatchRenderedOutput('0');
344
});
345
@@ -387,7 +386,7 @@ describe('ReactLazyContextPropagation', () => {
386
await act(async () => {
387
root.render(<App />);
388
});
390
- expect(Scheduler).toHaveYielded(['A', 'A']);
389
+ assertLog(['A', 'A']);
390
expect(root).toMatchRenderedOutput('AA');
391
392
await act(async () => {
@@ -395,13 +394,13 @@ describe('ReactLazyContextPropagation', () => {
394
// the fallback displays despite this being a refresh.
395
setContext('B');
396
});
398
- expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']);
397
+ assertLog(['Suspend! [B]', 'Loading...', 'B']);
398
expect(root).toMatchRenderedOutput('Loading...B');
399
400
await act(async () => {
401
await resolveText('B');
402
});
404
- expect(Scheduler).toHaveYielded(['B']);
403
+ assertLog(['B']);
404
expect(root).toMatchRenderedOutput('BB');
405
});
406
@@ -467,7 +466,7 @@ describe('ReactLazyContextPropagation', () => {
466
await act(async () => {
467
root.render(<App />);
468
});
470
- expect(Scheduler).toHaveYielded(['A', 'A', 'A']);
469
+ assertLog(['A', 'A', 'A']);
470
expect(root).toMatchRenderedOutput('AAA');
471
472
await act(async () => {
@@ -475,13 +474,13 @@ describe('ReactLazyContextPropagation', () => {
474
// the fallback displays despite this being a refresh.
475
setContext('B');
476
});
478
- expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']);
477
+ assertLog(['Suspend! [B]', 'Loading...', 'B']);
478
expect(root).toMatchRenderedOutput('Loading...B');
479
480
await act(async () => {
481
await resolveText('B');
482
});
484
- expect(Scheduler).toHaveYielded(['B', 'B']);
483
+ assertLog(['B', 'B']);
484
expect(root).toMatchRenderedOutput('BBB');
485
});
486
@@ -528,7 +527,7 @@ describe('ReactLazyContextPropagation', () => {
527
await act(async () => {
528
root.render(<App />);
529
});
531
- expect(Scheduler).toHaveYielded(['A', 'A']);
530
+ assertLog(['A', 'A']);
531
expect(root).toMatchRenderedOutput('AA');
532
533
await act(async () => {
@@ -536,13 +535,13 @@ describe('ReactLazyContextPropagation', () => {
535
// the fallback displays despite this being a refresh.
536
setContext('B');
537
});
539
- expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']);
538
+ assertLog(['Suspend! [B]', 'Loading...', 'B']);
539
expect(root).toMatchRenderedOutput('Loading...B');
540
541
await act(async () => {
542
await resolveText('B');
543
});
545
- expect(Scheduler).toHaveYielded(['B']);
544
+ assertLog(['B']);
545
expect(root).toMatchRenderedOutput('BB');
546
});
547
@@ -582,13 +581,13 @@ describe('ReactLazyContextPropagation', () => {
581
await act(async () => {
582
root.render(<App />);
583
});
585
- expect(Scheduler).toHaveYielded(['A', 'A']);
584
+ assertLog(['A', 'A']);
585
expect(root).toMatchRenderedOutput('AA');
586
587
await act(async () => {
588
setContext('B');
589
});
591
- expect(Scheduler).toHaveYielded(['B', 'B']);
590
+ assertLog(['B', 'B']);
591
expect(root).toMatchRenderedOutput('BB');
592
});
593
@@ -643,13 +642,13 @@ describe('ReactLazyContextPropagation', () => {
642
await act(async () => {
643
root.render(<App />);
644
});
646
- expect(Scheduler).toHaveYielded(['A', 'A', 'A']);
645
+ assertLog(['A', 'A', 'A']);
646
expect(root).toMatchRenderedOutput('AAA');
647
648
await act(async () => {
649
setContext('B');
650
});
652
- expect(Scheduler).toHaveYielded(['B', 'B', 'B']);
651
+ assertLog(['B', 'B', 'B']);
652
expect(root).toMatchRenderedOutput('BBB');
653
});
654
@@ -685,13 +684,13 @@ describe('ReactLazyContextPropagation', () => {
684
await act(async () => {
685
root.render(<App />);
686
});
688
- expect(Scheduler).toHaveYielded(['A', 'A']);
687
+ assertLog(['A', 'A']);
688
expect(root).toMatchRenderedOutput('AA');
689
690
await act(async () => {
691
setContext('B');
692
});
694
- expect(Scheduler).toHaveYielded(['B', 'B']);
693
+ assertLog(['B', 'B']);
694
expect(root).toMatchRenderedOutput('BB');
695
});
696
@@ -739,13 +738,13 @@ describe('ReactLazyContextPropagation', () => {
738
await act(async () => {
739
root.render(<App />);
740
});
742
- expect(Scheduler).toHaveYielded(['A', 'A']);
741
+ assertLog(['A', 'A']);
742
expect(root).toMatchRenderedOutput('AA');
743
744
await act(async () => {
745
setContext('B');
746
});
748
- expect(Scheduler).toHaveYielded(['B', 'B']);
747
+ assertLog(['B', 'B']);
748
expect(root).toMatchRenderedOutput('BB');
749
});
750
@@ -802,19 +801,19 @@ describe('ReactLazyContextPropagation', () => {
801
await act(async () => {
802
root.render(<App />);
803
});
805
- expect(Scheduler).toHaveYielded(['A', 'A']);
804
+ assertLog(['A', 'A']);
805
expect(root).toMatchRenderedOutput('AA');
806
807
await act(async () => {
808
setContext('B');
809
});
811
- expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...']);
810
+ assertLog(['Suspend! [B]', 'Loading...']);
811
expect(root).toMatchRenderedOutput('Loading...');
812
813
await act(async () => {
814
await resolveText('B');
815
});
817
- expect(Scheduler).toHaveYielded(['B', 'B']);
816
+ assertLog(['B', 'B']);
817
expect(root).toMatchRenderedOutput('BB');
818
});
819
@@ -863,13 +862,13 @@ describe('ReactLazyContextPropagation', () => {
862
await act(async () => {
863
root.render(<App />);
864
});
866
- expect(Scheduler).toHaveYielded(['A', 'A']);
865
+ assertLog(['A', 'A']);
866
expect(root).toMatchRenderedOutput('AA');
867
868
await act(async () => {
869
setContext('B');
870
});
872
- expect(Scheduler).toHaveYielded(['B', 'B']);
871
+ assertLog(['B', 'B']);
872
expect(root).toMatchRenderedOutput('BB');
873
});
874
@@ -912,13 +911,13 @@ describe('ReactLazyContextPropagation', () => {
911
await act(async () => {
912
root.render(<App />);
913
});
915
- expect(Scheduler).toHaveYielded(['A', 'A']);
914
+ assertLog(['A', 'A']);
915
expect(root).toMatchRenderedOutput('AA');
916
917
await act(async () => {
918
setContext('B');
919
});
921
- expect(Scheduler).toHaveYielded(['B', 'B']);
920
+ assertLog(['B', 'B']);
921
expect(root).toMatchRenderedOutput('BB');
922
});
923
});
packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js
+22
-25
@@ -15,6 +15,8 @@ let startTransition;
15
let useDeferredValue;
16
let useMemo;
17
let useState;
18
+let assertLog;
19
+let waitForPaint;
20
21
describe('ReactDeferredValue', () => {
22
beforeEach(() => {
@@ -28,6 +30,10 @@ describe('ReactDeferredValue', () => {
30
useDeferredValue = React.useDeferredValue;
31
useMemo = React.useMemo;
32
useState = React.useState;
33
+
34
+ const InternalTestUtils = require('internal-test-utils');
35
+ assertLog = InternalTestUtils.assertLog;
36
+ waitForPaint = InternalTestUtils.waitForPaint;
37
});
38
39
function Text({text}) {
@@ -65,15 +71,14 @@ describe('ReactDeferredValue', () => {
71
await act(async () => {
72
root.render(<App value={1} />);
73
});
68
- expect(Scheduler).toHaveYielded(['Original: 1', 'Deferred: 1']);
74
+ assertLog(['Original: 1', 'Deferred: 1']);
75
76
// If it's an urgent update, the value is deferred
77
await act(async () => {
78
root.render(<App value={2} />);
79
74
- expect(Scheduler).toFlushUntilNextPaint(['Original: 2']);
75
- // The deferred value updates in a separate render
76
- expect(Scheduler).toFlushUntilNextPaint(['Deferred: 2']);
80
+ await waitForPaint(['Original: 2']);
81
+ await waitForPaint(['Deferred: 2']);
82
});
83
expect(root).toMatchRenderedOutput(
84
<div>
@@ -87,8 +92,7 @@ describe('ReactDeferredValue', () => {
92
startTransition(() => {
93
root.render(<App value={3} />);
94
});
90
- // The deferred value updates in the same render as the original
91
- expect(Scheduler).toFlushUntilNextPaint(['Original: 3', 'Deferred: 3']);
95
+ await waitForPaint(['Original: 3', 'Deferred: 3']);
96
});
97
expect(root).toMatchRenderedOutput(
98
<div>
@@ -126,15 +130,14 @@ describe('ReactDeferredValue', () => {
130
await act(async () => {
131
root.render(<App value={1} />);
132
});
129
- expect(Scheduler).toHaveYielded(['Original: 1', 'Deferred: 1']);
133
+ assertLog(['Original: 1', 'Deferred: 1']);
134
135
// If it's an urgent update, the value is deferred
136
await act(async () => {
137
root.render(<App value={2} />);
138
135
- expect(Scheduler).toFlushUntilNextPaint(['Original: 2']);
136
- // The deferred value updates in a separate render
137
- expect(Scheduler).toFlushUntilNextPaint(['Deferred: 2']);
139
+ await waitForPaint(['Original: 2']);
140
+ await waitForPaint(['Deferred: 2']);
141
});
142
expect(root).toMatchRenderedOutput(
143
<div>
@@ -148,8 +151,7 @@ describe('ReactDeferredValue', () => {
151
startTransition(() => {
152
root.render(<App value={3} />);
153
});
151
- // The deferred value updates in the same render as the original
152
- expect(Scheduler).toFlushUntilNextPaint(['Original: 3', 'Deferred: 3']);
154
+ await waitForPaint(['Original: 3', 'Deferred: 3']);
155
});
156
expect(root).toMatchRenderedOutput(
157
<div>
@@ -192,15 +194,14 @@ describe('ReactDeferredValue', () => {
194
await act(async () => {
195
root.render(<App value={1} />);
196
});
195
- expect(Scheduler).toHaveYielded(['Original: 1', 'Deferred: 1']);
197
+ assertLog(['Original: 1', 'Deferred: 1']);
198
199
// If it's an urgent update, the value is deferred
200
await act(async () => {
201
root.render(<App value={2} />);
202
201
- expect(Scheduler).toFlushUntilNextPaint(['Original: 2']);
202
- // The deferred value updates in a separate render
203
- expect(Scheduler).toFlushUntilNextPaint(['Deferred: 2']);
203
+ await waitForPaint(['Original: 2']);
204
+ await waitForPaint(['Deferred: 2']);
205
});
206
expect(root).toMatchRenderedOutput(
207
<div>
@@ -214,8 +215,7 @@ describe('ReactDeferredValue', () => {
215
startTransition(() => {
216
root.render(<App value={3} />);
217
});
217
- // The deferred value updates in the same render as the original
218
- expect(Scheduler).toFlushUntilNextPaint(['Original: 3', 'Deferred: 3']);
218
+ await waitForPaint(['Original: 3', 'Deferred: 3']);
219
});
220
expect(root).toMatchRenderedOutput(
221
<div>
@@ -257,7 +257,7 @@ describe('ReactDeferredValue', () => {
257
// Initial render
258
await act(async () => {
259
root.render(<App value={1} />);
260
- expect(Scheduler).toFlushUntilNextPaint(['Original: 1', 'Deferred: 1']);
260
+ await waitForPaint(['Original: 1', 'Deferred: 1']);
261
expect(root).toMatchRenderedOutput(
262
<div>
263
<div>Original: 1</div>
@@ -270,7 +270,7 @@ describe('ReactDeferredValue', () => {
270
startTransition(() => {
271
root.render(<App value={2} />);
272
});
273
- expect(Scheduler).toFlushUntilNextPaint(['Original: 2', 'Deferred: 2']);
273
+ await waitForPaint(['Original: 2', 'Deferred: 2']);
274
expect(root).toMatchRenderedOutput(
275
<div>
276
<div>Original: 2</div>
@@ -281,17 +281,14 @@ describe('ReactDeferredValue', () => {
281
282
await act(async () => {
283
root.render(<App value={3} />);
284
- // In the regression, the memoized value was not updated during non-urgent
285
- // updates, so this would flip the deferred value back to the initial
286
- // value (1) instead of reusing the current one (2).
287
- expect(Scheduler).toFlushUntilNextPaint(['Original: 3']);
284
+ await waitForPaint(['Original: 3']);
285
expect(root).toMatchRenderedOutput(
286
<div>
287
<div>Original: 3</div>
288
<div>Deferred: 2</div>
289
</div>,
290
);
294
- expect(Scheduler).toFlushUntilNextPaint(['Deferred: 3']);
291
+ await waitForPaint(['Deferred: 3']);
292
expect(root).toMatchRenderedOutput(
293
<div>
294
<div>Original: 3</div>
packages/react-reconciler/src/__tests__/ReactDisableSchedulerTimeoutBasedOnReactExpirationTime-test.internal.js
+7
-7
@@ -5,6 +5,7 @@ let Scheduler;
5
let Suspense;
6
let scheduleCallback;
7
let NormalPriority;
8
+let waitForAll;
9
10
describe('ReactSuspenseList', () => {
11
beforeEach(() => {
@@ -20,6 +21,9 @@ describe('ReactSuspenseList', () => {
21
22
scheduleCallback = Scheduler.unstable_scheduleCallback;
23
NormalPriority = Scheduler.unstable_NormalPriority;
24
+
25
+ const InternalTestUtils = require('internal-test-utils');
26
+ waitForAll = InternalTestUtils.waitForAll;
27
});
28
29
function Text(props) {
@@ -61,16 +65,12 @@ describe('ReactSuspenseList', () => {
65
const root = ReactNoop.createRoot(null);
66
67
root.render(<App show={false} />);
64
- expect(Scheduler).toFlushAndYield([]);
68
+ await waitForAll([]);
69
70
React.startTransition(() => {
71
root.render(<App show={true} />);
72
});
69
- expect(Scheduler).toFlushAndYield([
70
- 'Suspend! [A]',
71
- 'Suspend! [B]',
72
- 'Loading...',
73
- ]);
73
+ await waitForAll(['Suspend! [A]', 'Suspend! [B]', 'Loading...']);
74
expect(root).toMatchRenderedOutput(null);
75
76
Scheduler.unstable_advanceTime(2000);
@@ -92,7 +92,7 @@ describe('ReactSuspenseList', () => {
92
// task should not jump the queue ahead of B.
93
await expect(Scheduler).toFlushAndYieldThrough(['Resolve B']);
94
95
- expect(Scheduler).toFlushAndYield(['A', 'B']);
95
+ await waitForAll(['A', 'B']);
96
expect(root).toMatchRenderedOutput('AB');
97
});
98
});
packages/react-reconciler/src/__tests__/ReactEffectOrdering-test.js
+7
-3
@@ -18,8 +18,9 @@ let Scheduler;
18
let act;
19
let useEffect;
20
let useLayoutEffect;
21
+let assertLog;
22
22
-describe('ReactHooksWithNoopRenderer', () => {
23
+describe('ReactEffectOrdering', () => {
24
beforeEach(() => {
25
jest.resetModules();
26
jest.useFakeTimers();
@@ -30,6 +31,9 @@ describe('ReactHooksWithNoopRenderer', () => {
31
act = require('jest-react').act;
32
useEffect = React.useEffect;
33
useLayoutEffect = React.useLayoutEffect;
34
+
35
+ const InternalTestUtils = require('internal-test-utils');
36
+ assertLog = InternalTestUtils.assertLog;
37
});
38
39
test('layout unmounts on deletion are fired in parent -> child order', async () => {
@@ -56,7 +60,7 @@ describe('ReactHooksWithNoopRenderer', () => {
60
await act(async () => {
61
root.render(null);
62
});
59
- expect(Scheduler).toHaveYielded(['Unmount parent', 'Unmount child']);
63
+ assertLog(['Unmount parent', 'Unmount child']);
64
});
65
66
test('passive unmounts on deletion are fired in parent -> child order', async () => {
@@ -83,6 +87,6 @@ describe('ReactHooksWithNoopRenderer', () => {
87
await act(async () => {
88
root.render(null);
89
});
86
- expect(Scheduler).toHaveYielded(['Unmount parent', 'Unmount child']);
90
+ assertLog(['Unmount parent', 'Unmount child']);
91
});
92
});
packages/react-reconciler/src/__tests__/ReactExpiration-test.js
+67
-86
@@ -18,6 +18,9 @@ let resolveText;
18
let startTransition;
19
let useState;
20
let useEffect;
21
+let assertLog;
22
+let waitFor;
23
+let waitForAll;
24
25
describe('ReactExpiration', () => {
26
beforeEach(() => {
@@ -31,6 +34,11 @@ describe('ReactExpiration', () => {
34
useState = React.useState;
35
useEffect = React.useEffect;
36
37
+ const InternalTestUtils = require('internal-test-utils');
38
+ assertLog = InternalTestUtils.assertLog;
39
+ waitFor = InternalTestUtils.waitFor;
40
+ waitForAll = InternalTestUtils.waitForAll;
41
+
42
const textCache = new Map();
43
44
readText = text => {
@@ -136,7 +144,7 @@ describe('ReactExpiration', () => {
144
expect(ReactNoop).toMatchRenderedOutput(<span prop="done" />);
145
});
146
139
- it('two updates of like priority in the same event always flush within the same batch', () => {
147
+ it('two updates of like priority in the same event always flush within the same batch', async () => {
148
class TextClass extends React.Component {
149
componentDidMount() {
150
Scheduler.unstable_yieldValue(`${this.props.text} [commit]`);
@@ -163,37 +171,32 @@ describe('ReactExpiration', () => {
171
});
172
// Advance the timer.
173
Scheduler.unstable_advanceTime(2000);
166
- // Partially flush the first update, then interrupt it.
167
- expect(Scheduler).toFlushAndYieldThrough(['A [render]']);
174
+ await waitFor(['A [render]']);
175
interrupt();
176
170
- // Don't advance time by enough to expire the first update.
171
- expect(Scheduler).toHaveYielded([]);
177
+ assertLog([]);
178
expect(ReactNoop).toMatchRenderedOutput(null);
179
180
// Schedule another update.
181
ReactNoop.render(<TextClass text="B" />);
176
- // Both updates are batched
177
- expect(Scheduler).toFlushAndYield(['B [render]', 'B [commit]']);
182
+ await waitForAll(['B [render]', 'B [commit]']);
183
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
184
185
// Now do the same thing again, except this time don't flush any work in
186
// between the two updates.
187
ReactNoop.render(<TextClass text="A" />);
188
Scheduler.unstable_advanceTime(2000);
184
- expect(Scheduler).toHaveYielded([]);
189
+ assertLog([]);
190
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
191
// Schedule another update.
192
ReactNoop.render(<TextClass text="B" />);
188
- // The updates should flush in the same batch, since as far as the scheduler
189
- // knows, they may have occurred inside the same event.
190
- expect(Scheduler).toFlushAndYield(['B [render]', 'B [commit]']);
193
+ await waitForAll(['B [render]', 'B [commit]']);
194
});
195
196
it(
197
'two updates of like priority in the same event always flush within the ' +
198
"same batch, even if there's a sync update in between",
196
- () => {
199
+ async () => {
200
class TextClass extends React.Component {
201
componentDidMount() {
202
Scheduler.unstable_yieldValue(`${this.props.text} [commit]`);
@@ -220,25 +223,22 @@ describe('ReactExpiration', () => {
223
});
224
// Advance the timer.
225
Scheduler.unstable_advanceTime(2000);
223
- // Partially flush the first update, then interrupt it.
224
- expect(Scheduler).toFlushAndYieldThrough(['A [render]']);
226
+ await waitFor(['A [render]']);
227
interrupt();
228
227
- // Don't advance time by enough to expire the first update.
228
- expect(Scheduler).toHaveYielded([]);
229
+ assertLog([]);
230
expect(ReactNoop).toMatchRenderedOutput(null);
231
232
// Schedule another update.
233
ReactNoop.render(<TextClass text="B" />);
233
- // Both updates are batched
234
- expect(Scheduler).toFlushAndYield(['B [render]', 'B [commit]']);
234
+ await waitForAll(['B [render]', 'B [commit]']);
235
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
236
237
// Now do the same thing again, except this time don't flush any work in
238
// between the two updates.
239
ReactNoop.render(<TextClass text="A" />);
240
Scheduler.unstable_advanceTime(2000);
241
- expect(Scheduler).toHaveYielded([]);
241
+ assertLog([]);
242
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
243
244
// Perform some synchronous work. The scheduler must assume we're inside
@@ -247,13 +247,11 @@ describe('ReactExpiration', () => {
247
248
// Schedule another update.
249
ReactNoop.render(<TextClass text="B" />);
250
- // The updates should flush in the same batch, since as far as the scheduler
251
- // knows, they may have occurred inside the same event.
252
- expect(Scheduler).toFlushAndYield(['B [render]', 'B [commit]']);
250
+ await waitForAll(['B [render]', 'B [commit]']);
251
},
252
);
253
256
- it('cannot update at the same expiration time that is already rendering', () => {
254
+ it('cannot update at the same expiration time that is already rendering', async () => {
255
const store = {text: 'initial'};
256
const subscribers = [];
257
class Connected extends React.Component {
@@ -292,7 +290,7 @@ describe('ReactExpiration', () => {
290
React.startTransition(() => {
291
ReactNoop.render(<App />);
292
});
295
- expect(Scheduler).toFlushAndYield([
293
+ await waitForAll([
294
'initial [A] [render]',
295
'initial [B] [render]',
296
'initial [C] [render]',
@@ -307,10 +305,7 @@ describe('ReactExpiration', () => {
305
React.startTransition(() => {
306
subscribers.forEach(s => s.setState({text: '1'}));
307
});
310
- expect(Scheduler).toFlushAndYieldThrough([
311
- '1 [A] [render]',
312
- '1 [B] [render]',
313
- ]);
308
+ await waitFor(['1 [A] [render]', '1 [B] [render]']);
309
310
// Before the update can finish, update again. Even though no time has
311
// advanced, this update should be given a different expiration time than
@@ -318,13 +313,10 @@ describe('ReactExpiration', () => {
313
React.startTransition(() => {
314
subscribers.forEach(s => s.setState({text: '2'}));
315
});
321
- expect(Scheduler).toFlushAndYieldThrough([
322
- '1 [C] [render]',
323
- '1 [D] [render]',
324
- ]);
316
+ await waitFor(['1 [C] [render]', '1 [D] [render]']);
317
});
318
327
- it('stops yielding if CPU-bound update takes too long to finish', () => {
319
+ it('stops yielding if CPU-bound update takes too long to finish', async () => {
320
const root = ReactNoop.createRoot();
321
function App() {
322
return (
@@ -342,18 +334,18 @@ describe('ReactExpiration', () => {
334
root.render(<App />);
335
});
336
345
- expect(Scheduler).toFlushAndYieldThrough(['A']);
346
- expect(Scheduler).toFlushAndYieldThrough(['B']);
347
- expect(Scheduler).toFlushAndYieldThrough(['C']);
337
+ await waitFor(['A']);
338
+ await waitFor(['B']);
339
+ await waitFor(['C']);
340
341
Scheduler.unstable_advanceTime(10000);
342
343
flushNextRenderIfExpired();
352
- expect(Scheduler).toHaveYielded(['D', 'E']);
344
+ assertLog(['D', 'E']);
345
expect(root).toMatchRenderedOutput('ABCDE');
346
});
347
356
- it('root expiration is measured from the time of the first update', () => {
348
+ it('root expiration is measured from the time of the first update', async () => {
349
Scheduler.unstable_advanceTime(10000);
350
351
const root = ReactNoop.createRoot();
@@ -372,14 +364,14 @@ describe('ReactExpiration', () => {
364
root.render(<App />);
365
});
366
375
- expect(Scheduler).toFlushAndYieldThrough(['A']);
376
- expect(Scheduler).toFlushAndYieldThrough(['B']);
377
- expect(Scheduler).toFlushAndYieldThrough(['C']);
367
+ await waitFor(['A']);
368
+ await waitFor(['B']);
369
+ await waitFor(['C']);
370
371
Scheduler.unstable_advanceTime(10000);
372
373
flushNextRenderIfExpired();
382
- expect(Scheduler).toHaveYielded(['D', 'E']);
374
+ assertLog(['D', 'E']);
375
expect(root).toMatchRenderedOutput('ABCDE');
376
});
377
@@ -404,14 +396,14 @@ describe('ReactExpiration', () => {
396
397
// The update should not have expired yet.
398
flushNextRenderIfExpired();
407
- expect(Scheduler).toHaveYielded([]);
399
+ assertLog([]);
400
401
expect(ReactNoop).toMatchRenderedOutput(null);
402
403
// Advance the time some more to expire the update.
404
Scheduler.unstable_advanceTime(10000);
405
flushNextRenderIfExpired();
414
- expect(Scheduler).toHaveYielded([]);
406
+ assertLog([]);
407
expect(ReactNoop).toMatchRenderedOutput('Hi');
408
});
409
@@ -427,14 +419,14 @@ describe('ReactExpiration', () => {
419
ReactNoop.render('Hi');
420
});
421
flushNextRenderIfExpired();
430
- expect(Scheduler).toHaveYielded([]);
422
+ assertLog([]);
423
expect(ReactNoop).toMatchRenderedOutput(null);
424
425
// Advancing by ~5 seconds should be sufficient to expire the update. (I
426
// used a slightly larger number to allow for possible rounding.)
427
Scheduler.unstable_advanceTime(6000);
428
flushNextRenderIfExpired();
437
- expect(Scheduler).toHaveYielded([]);
429
+ assertLog([]);
430
expect(ReactNoop).toMatchRenderedOutput('Hi');
431
});
432
@@ -463,7 +455,7 @@ describe('ReactExpiration', () => {
455
await act(async () => {
456
root.render(<App />);
457
});
466
- expect(Scheduler).toHaveYielded(['Sync pri: 0', 'Normal pri: 0']);
458
+ assertLog(['Sync pri: 0', 'Normal pri: 0']);
459
expect(root).toMatchRenderedOutput('Sync pri: 0, Normal pri: 0');
460
461
// First demonstrate what happens when there's no starvation
@@ -471,18 +463,16 @@ describe('ReactExpiration', () => {
463
React.startTransition(() => {
464
updateNormalPri();
465
});
474
- expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 0']);
466
+ await waitFor(['Sync pri: 0']);
467
updateSyncPri();
476
- expect(Scheduler).toHaveYielded(['Sync pri: 1', 'Normal pri: 0']);
468
+ assertLog(['Sync pri: 1', 'Normal pri: 0']);
469
470
// The remaining work hasn't expired, so the render phase is time sliced.
471
// In other words, we can flush just the first child without flushing
472
// the rest.
473
Scheduler.unstable_flushNumberOfYields(1);
482
- // Yield right after first child.
483
- expect(Scheduler).toHaveYielded(['Sync pri: 1']);
484
- // Now do the rest.
485
- expect(Scheduler).toFlushAndYield(['Normal pri: 1']);
474
+ assertLog(['Sync pri: 1']);
475
+ await waitForAll(['Normal pri: 1']);
476
});
477
expect(root).toMatchRenderedOutput('Sync pri: 1, Normal pri: 1');
478
@@ -491,7 +481,7 @@ describe('ReactExpiration', () => {
481
React.startTransition(() => {
482
updateNormalPri();
483
});
494
- expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 1']);
484
+ await waitFor(['Sync pri: 1']);
485
486
// This time, a lot of time has elapsed since the normal pri update
487
// started rendering. (This should advance time by some number that's
@@ -500,12 +490,12 @@ describe('ReactExpiration', () => {
490
Scheduler.unstable_advanceTime(10000);
491
492
updateSyncPri();
503
- expect(Scheduler).toHaveYielded(['Sync pri: 2', 'Normal pri: 1']);
493
+ assertLog(['Sync pri: 2', 'Normal pri: 1']);
494
495
// The remaining work _has_ expired, so the render phase is _not_ time
496
// sliced. Attempting to flush just the first child also flushes the rest.
497
Scheduler.unstable_flushNumberOfYields(1);
508
- expect(Scheduler).toHaveYielded(['Sync pri: 2', 'Normal pri: 2']);
498
+ assertLog(['Sync pri: 2', 'Normal pri: 2']);
499
});
500
expect(root).toMatchRenderedOutput('Sync pri: 2, Normal pri: 2');
501
});
@@ -534,16 +524,16 @@ describe('ReactExpiration', () => {
524
await act(async () => {
525
root.render(<App />);
526
});
537
- expect(Scheduler).toHaveYielded(['Sync pri: 0', 'Idle pri: 0']);
527
+ assertLog(['Sync pri: 0', 'Idle pri: 0']);
528
expect(root).toMatchRenderedOutput('Sync pri: 0, Idle pri: 0');
529
530
// First demonstrate what happens when there's no starvation
531
await act(async () => {
532
updateIdlePri();
543
- expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 0']);
533
+ await waitFor(['Sync pri: 0']);
534
updateSyncPri();
535
});
546
- expect(Scheduler).toHaveYielded([
536
+ assertLog([
537
// Interrupt idle update to render sync update
538
'Sync pri: 1',
539
'Idle pri: 0',
@@ -556,7 +546,7 @@ describe('ReactExpiration', () => {
546
// Do the same thing, but starve the first update
547
await act(async () => {
548
updateIdlePri();
559
- expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 1']);
549
+ await waitFor(['Sync pri: 1']);
550
551
// Advance a ridiculously large amount of time to demonstrate that the
552
// idle work never expires
@@ -564,8 +554,7 @@ describe('ReactExpiration', () => {
554
555
updateSyncPri();
556
});
567
- // Same thing should happen as last time
568
- expect(Scheduler).toHaveYielded([
557
+ assertLog([
558
// Interrupt idle update to render sync update
559
'Sync pri: 2',
560
'Idle pri: 1',
@@ -597,14 +586,14 @@ describe('ReactExpiration', () => {
586
await act(async () => {
587
root.render(<App />);
588
});
600
- expect(Scheduler).toHaveYielded(['A0', 'B0', 'C']);
589
+ assertLog(['A0', 'B0', 'C']);
590
expect(root).toMatchRenderedOutput('A0B0C');
591
592
await act(async () => {
593
startTransition(() => {
594
setA(1);
595
});
607
- expect(Scheduler).toFlushAndYieldThrough(['A1']);
596
+ await waitFor(['A1']);
597
startTransition(() => {
598
setB(1);
599
});
@@ -614,12 +603,12 @@ describe('ReactExpiration', () => {
603
// (entangled), we should be able to finish the in-progress transition
604
// without also including the next one.
605
Scheduler.unstable_flushNumberOfYields(1);
617
- expect(Scheduler).toHaveYielded(['B0', 'C']);
606
+ assertLog(['B0', 'C']);
607
expect(root).toMatchRenderedOutput('A1B0C');
608
609
// The next transition also finishes without yielding.
610
Scheduler.unstable_flushNumberOfYields(1);
622
- expect(Scheduler).toHaveYielded(['A1', 'B1', 'C']);
611
+ assertLog(['A1', 'B1', 'C']);
612
expect(root).toMatchRenderedOutput('A1B1C');
613
});
614
});
@@ -642,28 +631,21 @@ describe('ReactExpiration', () => {
631
await resolveText('A0');
632
root.render(<App step={0} />);
633
});
645
- expect(Scheduler).toHaveYielded(['A0', 'B', 'C']);
634
+ assertLog(['A0', 'B', 'C']);
635
expect(root).toMatchRenderedOutput('A0BC');
636
637
await act(async () => {
638
React.startTransition(() => {
639
root.render(<App step={1} />);
640
});
652
- expect(Scheduler).toFlushAndYield([
653
- 'Suspend! [A1]',
654
- 'B',
655
- 'C',
656
- 'Loading...',
657
- ]);
641
+ await waitForAll(['Suspend! [A1]', 'B', 'C', 'Loading...']);
642
643
// Lots of time elapses before the promise resolves
644
Scheduler.unstable_advanceTime(10000);
645
await resolveText('A1');
662
- expect(Scheduler).toHaveYielded(['Promise resolved [A1]']);
646
+ assertLog(['Promise resolved [A1]']);
647
664
- // But the update doesn't expire, because it was IO bound. So we can
665
- // partially rendering without finishing.
666
- expect(Scheduler).toFlushAndYieldThrough(['A1']);
648
+ await waitFor(['A1']);
649
expect(root).toMatchRenderedOutput('A0BC');
650
651
// Lots more time elapses. We're CPU-bound now, so we should treat this
@@ -672,7 +654,7 @@ describe('ReactExpiration', () => {
654
655
// The rest of the update finishes without yielding.
656
Scheduler.unstable_flushNumberOfYields(1);
675
- expect(Scheduler).toHaveYielded(['B', 'C']);
657
+ assertLog(['B', 'C']);
658
});
659
});
660
@@ -696,13 +678,13 @@ describe('ReactExpiration', () => {
678
await act(async () => {
679
root.render(<App />);
680
});
699
- expect(Scheduler).toHaveYielded(['A0', 'B0']);
681
+ assertLog(['A0', 'B0']);
682
683
await act(async () => {
684
startTransition(() => {
685
setA(1);
686
});
705
- expect(Scheduler).toFlushAndYieldThrough(['A1']);
687
+ await waitFor(['A1']);
688
689
// Expire the in-progress update
690
Scheduler.unstable_advanceTime(10000);
@@ -710,12 +692,12 @@ describe('ReactExpiration', () => {
692
ReactNoop.flushSync(() => {
693
setB(1);
694
});
713
- expect(Scheduler).toHaveYielded(['A0', 'B1']);
695
+ assertLog(['A0', 'B1']);
696
697
// Now flush the original update. Because it expired, it should finish
698
// without yielding.
699
Scheduler.unstable_flushNumberOfYields(1);
718
- expect(Scheduler).toHaveYielded(['A1', 'B1']);
700
+ assertLog(['A1', 'B1']);
701
});
702
});
703
@@ -737,7 +719,7 @@ describe('ReactExpiration', () => {
719
await act(async () => {
720
root.render(<App step={0} />);
721
});
740
- expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0', 'Effect: 0']);
722
+ assertLog(['A0', 'B0', 'C0', 'Effect: 0']);
723
expect(root).toMatchRenderedOutput('A0B0C0');
724
725
await act(async () => {
@@ -749,9 +731,8 @@ describe('ReactExpiration', () => {
731
732
// The update finishes without yielding. But it does not flush the effect.
733
Scheduler.unstable_flushNumberOfYields(1);
752
- expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']);
734
+ assertLog(['A1', 'B1', 'C1']);
735
});
754
- // The effect flushes after paint.
755
- expect(Scheduler).toHaveYielded(['Effect: 1']);
736
+ assertLog(['Effect: 1']);
737
});
738
});
packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
+37
-31
@@ -5,6 +5,8 @@ let act;
5
let useState;
6
let useEffect;
7
let startTransition;
8
+let assertLog;
9
+let waitForPaint;
10
11
// TODO: Migrate tests to React DOM instead of React Noop
12
@@ -19,6 +21,10 @@ describe('ReactFlushSync', () => {
21
useState = React.useState;
22
useEffect = React.useEffect;
23
startTransition = React.startTransition;
24
+
25
+ const InternalTestUtils = require('internal-test-utils');
26
+ assertLog = InternalTestUtils.assertLog;
27
+ waitForPaint = InternalTestUtils.waitForPaint;
28
});
29
30
function Text({text}) {
@@ -27,6 +33,8 @@ describe('ReactFlushSync', () => {
33
}
34
35
test('changes priority of updates in useEffect', async () => {
36
+ spyOnDev(console, 'error').mockImplementation(() => {});
37
+
38
function App() {
39
const [syncState, setSyncState] = useState(0);
40
const [state, setState] = useState(0);
@@ -44,29 +52,33 @@ describe('ReactFlushSync', () => {
52
React.startTransition(() => {
53
root.render(<App />);
54
});
47
- // This will yield right before the passive effect fires
48
- expect(Scheduler).toFlushUntilNextPaint(['0, 0']);
55
+ await waitForPaint(['0, 0']);
56
57
// The passive effect will schedule a sync update and a normal update.
58
// They should commit in two separate batches. First the sync one.
52
- expect(() => {
53
- expect(Scheduler).toFlushUntilNextPaint(
54
- gate(flags => flags.enableUnifiedSyncLane) ? ['1, 1'] : ['1, 0'],
55
- );
56
- }).toErrorDev('flushSync was called from inside a lifecycle method');
59
+ await waitForPaint(
60
+ gate(flags => flags.enableUnifiedSyncLane) ? ['1, 1'] : ['1, 0'],
61
+ );
62
63
// The remaining update is not sync
64
ReactNoop.flushSync();
60
- expect(Scheduler).toHaveYielded([]);
65
+ assertLog([]);
66
67
if (gate(flags => flags.enableUnifiedSyncLane)) {
63
- expect(Scheduler).toFlushUntilNextPaint([]);
68
+ await waitForPaint([]);
69
} else {
65
- // Now flush it.
66
- expect(Scheduler).toFlushUntilNextPaint(['1, 1']);
70
+ await waitForPaint(['1, 1']);
71
}
72
});
73
expect(root).toMatchRenderedOutput('1, 1');
74
+
75
+ if (__DEV__) {
76
+ expect(console.error.mock.calls[0][0]).toContain(
77
+ 'flushSync was called from inside a lifecycle method. React ' +
78
+ 'cannot flush when React is already rendering. Consider moving this ' +
79
+ 'call to a scheduler task or micro task.%s',
80
+ );
81
+ }
82
});
83
84
test('nested with startTransition', async () => {
@@ -84,7 +96,7 @@ describe('ReactFlushSync', () => {
96
await act(async () => {
97
root.render(<App />);
98
});
87
- expect(Scheduler).toHaveYielded(['0, 0']);
99
+ assertLog(['0, 0']);
100
expect(root).toMatchRenderedOutput('0, 0');
101
102
await act(async () => {
@@ -100,12 +112,10 @@ describe('ReactFlushSync', () => {
112
});
113
});
114
});
103
- // Only the sync update should have flushed
104
- expect(Scheduler).toHaveYielded(['1, 0']);
115
+ assertLog(['1, 0']);
116
expect(root).toMatchRenderedOutput('1, 0');
117
});
107
- // Now the async update has flushed, too.
108
- expect(Scheduler).toHaveYielded(['1, 1']);
118
+ assertLog(['1, 1']);
119
expect(root).toMatchRenderedOutput('1, 1');
120
});
121
@@ -122,7 +132,7 @@ describe('ReactFlushSync', () => {
132
ReactNoop.flushSync(() => {
133
root.render(<App />);
134
});
125
- expect(Scheduler).toHaveYielded([
135
+ assertLog([
136
'Child',
137
// Because the pending effect was the result of a sync update, calling
138
// flushSync should flush it.
@@ -145,15 +155,14 @@ describe('ReactFlushSync', () => {
155
ReactNoop.flushSync(() => {
156
root.render(<App />);
157
});
148
- expect(Scheduler).toHaveYielded([
158
+ assertLog([
159
'Child',
160
// Because we're in legacy mode, we shouldn't have flushed the passive
161
// effects yet.
162
]);
163
expect(root).toMatchRenderedOutput('Child');
164
});
155
- // Effect flushes after paint.
156
- expect(Scheduler).toHaveYielded(['Effect']);
165
+ assertLog(['Effect']);
166
});
167
168
test('flush pending passive effects before scope is called in legacy mode', async () => {
@@ -172,7 +181,7 @@ describe('ReactFlushSync', () => {
181
ReactNoop.flushSync(() => {
182
root.render(<App step={1} />);
183
});
175
- expect(Scheduler).toHaveYielded([
184
+ assertLog([
185
1,
186
// Because we're in legacy mode, we shouldn't have flushed the passive
187
// effects yet.
@@ -184,10 +193,10 @@ describe('ReactFlushSync', () => {
193
// fired, before the scope function is called.
194
root.render(<App step={currentStep + 1} />);
195
});
187
- expect(Scheduler).toHaveYielded(['Effect: 1', 2]);
196
+ assertLog(['Effect: 1', 2]);
197
expect(root).toMatchRenderedOutput('2');
198
});
190
- expect(Scheduler).toHaveYielded(['Effect: 2']);
199
+ assertLog(['Effect: 2']);
200
});
201
202
test("do not flush passive effects synchronously when they aren't the result of a sync render", async () => {
@@ -201,15 +210,14 @@ describe('ReactFlushSync', () => {
210
const root = ReactNoop.createRoot();
211
await act(async () => {
212
root.render(<App />);
204
- expect(Scheduler).toFlushUntilNextPaint([
213
+ await waitForPaint([
214
'Child',
215
// Because the passive effect was not the result of a sync update, it
216
// should not flush before paint.
217
]);
218
expect(root).toMatchRenderedOutput('Child');
219
});
211
- // Effect flushes after paint.
212
- expect(Scheduler).toHaveYielded(['Effect']);
220
+ assertLog(['Effect']);
221
});
222
223
test('does not flush pending passive effects', async () => {
@@ -223,15 +231,13 @@ describe('ReactFlushSync', () => {
231
const root = ReactNoop.createRoot();
232
await act(async () => {
233
root.render(<App />);
226
- expect(Scheduler).toFlushUntilNextPaint(['Child']);
234
+ await waitForPaint(['Child']);
235
expect(root).toMatchRenderedOutput('Child');
236
237
// Passive effects are pending. Calling flushSync should not affect them.
238
ReactNoop.flushSync();
231
- // Effects still haven't fired.
232
- expect(Scheduler).toHaveYielded([]);
239
+ assertLog([]);
240
});
234
- // Now the effects have fired.
235
- expect(Scheduler).toHaveYielded(['Effect']);
241
+ assertLog(['Effect']);
242
});
243
});
packages/react-reconciler/src/__tests__/ReactFragment-test.js
+86
-84
@@ -12,6 +12,7 @@
12
let React;
13
let ReactNoop;
14
let Scheduler;
15
+let waitForAll;
16
17
describe('ReactFragment', () => {
18
beforeEach(function () {
@@ -20,9 +21,12 @@ describe('ReactFragment', () => {
21
React = require('react');
22
ReactNoop = require('react-noop-renderer');
23
Scheduler = require('scheduler');
24
+
25
+ const InternalTestUtils = require('internal-test-utils');
26
+ waitForAll = InternalTestUtils.waitForAll;
27
});
28
25
- it('should render a single child via noop renderer', () => {
29
+ it('should render a single child via noop renderer', async () => {
30
const element = (
31
<>
32
<span>foo</span>
@@ -30,21 +34,21 @@ describe('ReactFragment', () => {
34
);
35
36
ReactNoop.render(element);
33
- expect(Scheduler).toFlushWithoutYielding();
37
+ await waitForAll([]);
38
39
expect(ReactNoop).toMatchRenderedOutput(<span>foo</span>);
40
});
41
38
- it('should render zero children via noop renderer', () => {
42
+ it('should render zero children via noop renderer', async () => {
43
const element = <React.Fragment />;
44
45
ReactNoop.render(element);
42
- expect(Scheduler).toFlushWithoutYielding();
46
+ await waitForAll([]);
47
48
expect(ReactNoop).toMatchRenderedOutput(null);
49
});
50
47
- it('should render multiple children via noop renderer', () => {
51
+ it('should render multiple children via noop renderer', async () => {
52
const element = (
53
<>
54
hello <span>world</span>
@@ -52,7 +56,7 @@ describe('ReactFragment', () => {
56
);
57
58
ReactNoop.render(element);
55
- expect(Scheduler).toFlushWithoutYielding();
59
+ await waitForAll([]);
60
61
expect(ReactNoop).toMatchRenderedOutput(
62
<>
@@ -61,13 +65,13 @@ describe('ReactFragment', () => {
65
);
66
});
67
64
- it('should render an iterable via noop renderer', () => {
68
+ it('should render an iterable via noop renderer', async () => {
69
const element = (
70
<>{new Set([<span key="a">hi</span>, <span key="b">bye</span>])}</>
71
);
72
73
ReactNoop.render(element);
70
- expect(Scheduler).toFlushWithoutYielding();
74
+ await waitForAll([]);
75
76
expect(ReactNoop).toMatchRenderedOutput(
77
<>
@@ -77,7 +81,7 @@ describe('ReactFragment', () => {
81
);
82
});
83
80
- it('should preserve state of children with 1 level nesting', function () {
84
+ it('should preserve state of children with 1 level nesting', async function () {
85
const ops = [];
86
87
class Stateful extends React.Component {
@@ -102,10 +106,10 @@ describe('ReactFragment', () => {
106
}
107
108
ReactNoop.render(<Foo condition={true} />);
105
- expect(Scheduler).toFlushWithoutYielding();
109
+ await waitForAll([]);
110
111
ReactNoop.render(<Foo condition={false} />);
108
- expect(Scheduler).toFlushWithoutYielding();
112
+ await waitForAll([]);
113
114
expect(ops).toEqual(['Update Stateful']);
115
expect(ReactNoop).toMatchRenderedOutput(
@@ -116,13 +120,13 @@ describe('ReactFragment', () => {
120
);
121
122
ReactNoop.render(<Foo condition={true} />);
119
- expect(Scheduler).toFlushWithoutYielding();
123
+ await waitForAll([]);
124
125
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
126
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
127
});
128
125
- it('should preserve state between top-level fragments', function () {
129
+ it('should preserve state between top-level fragments', async function () {
130
const ops = [];
131
132
class Stateful extends React.Component {
@@ -148,22 +152,22 @@ describe('ReactFragment', () => {
152
}
153
154
ReactNoop.render(<Foo condition={true} />);
151
- expect(Scheduler).toFlushWithoutYielding();
155
+ await waitForAll([]);
156
157
ReactNoop.render(<Foo condition={false} />);
154
- expect(Scheduler).toFlushWithoutYielding();
158
+ await waitForAll([]);
159
160
expect(ops).toEqual(['Update Stateful']);
161
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
162
163
ReactNoop.render(<Foo condition={true} />);
160
- expect(Scheduler).toFlushWithoutYielding();
164
+ await waitForAll([]);
165
166
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
167
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
168
});
169
166
- it('should preserve state of children nested at same level', function () {
170
+ it('should preserve state of children nested at same level', async function () {
171
const ops = [];
172
173
class Stateful extends React.Component {
@@ -198,10 +202,10 @@ describe('ReactFragment', () => {
202
}
203
204
ReactNoop.render(<Foo condition={true} />);
201
- expect(Scheduler).toFlushWithoutYielding();
205
+ await waitForAll([]);
206
207
ReactNoop.render(<Foo condition={false} />);
204
- expect(Scheduler).toFlushWithoutYielding();
208
+ await waitForAll([]);
209
210
expect(ops).toEqual(['Update Stateful']);
211
expect(ReactNoop).toMatchRenderedOutput(
@@ -212,13 +216,13 @@ describe('ReactFragment', () => {
216
);
217
218
ReactNoop.render(<Foo condition={true} />);
215
- expect(Scheduler).toFlushWithoutYielding();
219
+ await waitForAll([]);
220
221
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
222
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
223
});
224
221
- it('should not preserve state in non-top-level fragment nesting', function () {
225
+ it('should not preserve state in non-top-level fragment nesting', async function () {
226
const ops = [];
227
228
class Stateful extends React.Component {
@@ -246,22 +250,22 @@ describe('ReactFragment', () => {
250
}
251
252
ReactNoop.render(<Foo condition={true} />);
249
- expect(Scheduler).toFlushWithoutYielding();
253
+ await waitForAll([]);
254
255
ReactNoop.render(<Foo condition={false} />);
252
- expect(Scheduler).toFlushWithoutYielding();
256
+ await waitForAll([]);
257
258
expect(ops).toEqual([]);
259
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
260
261
ReactNoop.render(<Foo condition={true} />);
258
- expect(Scheduler).toFlushWithoutYielding();
262
+ await waitForAll([]);
263
264
expect(ops).toEqual([]);
265
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
266
});
267
264
- it('should not preserve state of children if nested 2 levels without siblings', function () {
268
+ it('should not preserve state of children if nested 2 levels without siblings', async function () {
269
const ops = [];
270
271
class Stateful extends React.Component {
@@ -287,22 +291,22 @@ describe('ReactFragment', () => {
291
}
292
293
ReactNoop.render(<Foo condition={true} />);
290
- expect(Scheduler).toFlushWithoutYielding();
294
+ await waitForAll([]);
295
296
ReactNoop.render(<Foo condition={false} />);
293
- expect(Scheduler).toFlushWithoutYielding();
297
+ await waitForAll([]);
298
299
expect(ops).toEqual([]);
300
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
301
302
ReactNoop.render(<Foo condition={true} />);
299
- expect(Scheduler).toFlushWithoutYielding();
303
+ await waitForAll([]);
304
305
expect(ops).toEqual([]);
306
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
307
});
308
305
- it('should not preserve state of children if nested 2 levels with siblings', function () {
309
+ it('should not preserve state of children if nested 2 levels with siblings', async function () {
310
const ops = [];
311
312
class Stateful extends React.Component {
@@ -329,10 +333,10 @@ describe('ReactFragment', () => {
333
}
334
335
ReactNoop.render(<Foo condition={true} />);
332
- expect(Scheduler).toFlushWithoutYielding();
336
+ await waitForAll([]);
337
338
ReactNoop.render(<Foo condition={false} />);
335
- expect(Scheduler).toFlushWithoutYielding();
339
+ await waitForAll([]);
340
341
expect(ops).toEqual([]);
342
expect(ReactNoop).toMatchRenderedOutput(
@@ -343,13 +347,13 @@ describe('ReactFragment', () => {
347
);
348
349
ReactNoop.render(<Foo condition={true} />);
346
- expect(Scheduler).toFlushWithoutYielding();
350
+ await waitForAll([]);
351
352
expect(ops).toEqual([]);
353
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
354
});
355
352
- it('should preserve state between array nested in fragment and fragment', function () {
356
+ it('should preserve state between array nested in fragment and fragment', async function () {
357
const ops = [];
358
359
class Stateful extends React.Component {
@@ -373,22 +377,22 @@ describe('ReactFragment', () => {
377
}
378
379
ReactNoop.render(<Foo condition={true} />);
376
- expect(Scheduler).toFlushWithoutYielding();
380
+ await waitForAll([]);
381
382
ReactNoop.render(<Foo condition={false} />);
379
- expect(Scheduler).toFlushWithoutYielding();
383
+ await waitForAll([]);
384
385
expect(ops).toEqual(['Update Stateful']);
386
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
387
388
ReactNoop.render(<Foo condition={true} />);
385
- expect(Scheduler).toFlushWithoutYielding();
389
+ await waitForAll([]);
390
391
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
392
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
393
});
394
391
- it('should preserve state between top level fragment and array', function () {
395
+ it('should preserve state between top level fragment and array', async function () {
396
const ops = [];
397
398
class Stateful extends React.Component {
@@ -412,22 +416,22 @@ describe('ReactFragment', () => {
416
}
417
418
ReactNoop.render(<Foo condition={true} />);
415
- expect(Scheduler).toFlushWithoutYielding();
419
+ await waitForAll([]);
420
421
ReactNoop.render(<Foo condition={false} />);
418
- expect(Scheduler).toFlushWithoutYielding();
422
+ await waitForAll([]);
423
424
expect(ops).toEqual(['Update Stateful']);
425
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
426
427
ReactNoop.render(<Foo condition={true} />);
424
- expect(Scheduler).toFlushWithoutYielding();
428
+ await waitForAll([]);
429
430
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
431
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
432
});
433
430
- it('should not preserve state between array nested in fragment and double nested fragment', function () {
434
+ it('should not preserve state between array nested in fragment and double nested fragment', async function () {
435
const ops = [];
436
437
class Stateful extends React.Component {
@@ -453,22 +457,22 @@ describe('ReactFragment', () => {
457
}
458
459
ReactNoop.render(<Foo condition={true} />);
456
- expect(Scheduler).toFlushWithoutYielding();
460
+ await waitForAll([]);
461
462
ReactNoop.render(<Foo condition={false} />);
459
- expect(Scheduler).toFlushWithoutYielding();
463
+ await waitForAll([]);
464
465
expect(ops).toEqual([]);
466
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
467
468
ReactNoop.render(<Foo condition={true} />);
465
- expect(Scheduler).toFlushWithoutYielding();
469
+ await waitForAll([]);
470
471
expect(ops).toEqual([]);
472
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
473
});
474
471
- it('should not preserve state between array nested in fragment and double nested array', function () {
475
+ it('should not preserve state between array nested in fragment and double nested array', async function () {
476
const ops = [];
477
478
class Stateful extends React.Component {
@@ -490,22 +494,22 @@ describe('ReactFragment', () => {
494
}
495
496
ReactNoop.render(<Foo condition={true} />);
493
- expect(Scheduler).toFlushWithoutYielding();
497
+ await waitForAll([]);
498
499
ReactNoop.render(<Foo condition={false} />);
496
- expect(Scheduler).toFlushWithoutYielding();
500
+ await waitForAll([]);
501
502
expect(ops).toEqual([]);
503
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
504
505
ReactNoop.render(<Foo condition={true} />);
502
- expect(Scheduler).toFlushWithoutYielding();
506
+ await waitForAll([]);
507
508
expect(ops).toEqual([]);
509
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
510
});
511
508
- it('should preserve state between double nested fragment and double nested array', function () {
512
+ it('should preserve state between double nested fragment and double nested array', async function () {
513
const ops = [];
514
515
class Stateful extends React.Component {
@@ -531,22 +535,22 @@ describe('ReactFragment', () => {
535
}
536
537
ReactNoop.render(<Foo condition={true} />);
534
- expect(Scheduler).toFlushWithoutYielding();
538
+ await waitForAll([]);
539
540
ReactNoop.render(<Foo condition={false} />);
537
- expect(Scheduler).toFlushWithoutYielding();
541
+ await waitForAll([]);
542
543
expect(ops).toEqual(['Update Stateful']);
544
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
545
546
ReactNoop.render(<Foo condition={true} />);
543
- expect(Scheduler).toFlushWithoutYielding();
547
+ await waitForAll([]);
548
549
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
550
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
551
});
552
549
- it('should not preserve state of children when the keys are different', function () {
553
+ it('should not preserve state of children when the keys are different', async function () {
554
const ops = [];
555
556
class Stateful extends React.Component {
@@ -573,10 +577,10 @@ describe('ReactFragment', () => {
577
}
578
579
ReactNoop.render(<Foo condition={true} />);
576
- expect(Scheduler).toFlushWithoutYielding();
580
+ await waitForAll([]);
581
582
ReactNoop.render(<Foo condition={false} />);
579
- expect(Scheduler).toFlushWithoutYielding();
583
+ await waitForAll([]);
584
585
expect(ops).toEqual([]);
586
expect(ReactNoop).toMatchRenderedOutput(
@@ -587,13 +591,13 @@ describe('ReactFragment', () => {
591
);
592
593
ReactNoop.render(<Foo condition={true} />);
590
- expect(Scheduler).toFlushWithoutYielding();
594
+ await waitForAll([]);
595
596
expect(ops).toEqual([]);
597
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
598
});
599
596
- it('should not preserve state between unkeyed and keyed fragment', function () {
600
+ it('should not preserve state between unkeyed and keyed fragment', async function () {
601
const ops = [];
602
603
class Stateful extends React.Component {
@@ -619,22 +623,22 @@ describe('ReactFragment', () => {
623
}
624
625
ReactNoop.render(<Foo condition={true} />);
622
- expect(Scheduler).toFlushWithoutYielding();
626
+ await waitForAll([]);
627
628
ReactNoop.render(<Foo condition={false} />);
625
- expect(Scheduler).toFlushWithoutYielding();
629
+ await waitForAll([]);
630
631
expect(ops).toEqual([]);
632
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
633
634
ReactNoop.render(<Foo condition={true} />);
631
- expect(Scheduler).toFlushWithoutYielding();
635
+ await waitForAll([]);
636
637
expect(ops).toEqual([]);
638
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
639
});
640
637
- it('should preserve state with reordering in multiple levels', function () {
641
+ it('should preserve state with reordering in multiple levels', async function () {
642
const ops = [];
643
644
class Stateful extends React.Component {
@@ -672,10 +676,10 @@ describe('ReactFragment', () => {
676
}
677
678
ReactNoop.render(<Foo condition={true} />);
675
- expect(Scheduler).toFlushWithoutYielding();
679
+ await waitForAll([]);
680
681
ReactNoop.render(<Foo condition={false} />);
678
- expect(Scheduler).toFlushWithoutYielding();
682
+ await waitForAll([]);
683
684
expect(ops).toEqual(['Update Stateful']);
685
expect(ReactNoop).toMatchRenderedOutput(
@@ -689,7 +693,7 @@ describe('ReactFragment', () => {
693
);
694
695
ReactNoop.render(<Foo condition={true} />);
692
- expect(Scheduler).toFlushWithoutYielding();
696
+ await waitForAll([]);
697
698
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
699
expect(ReactNoop).toMatchRenderedOutput(
@@ -703,7 +707,7 @@ describe('ReactFragment', () => {
707
);
708
});
709
706
- it('should not preserve state when switching to a keyed fragment to an array', function () {
710
+ it('should not preserve state when switching to a keyed fragment to an array', async function () {
711
const ops = [];
712
713
class Stateful extends React.Component {
@@ -735,7 +739,7 @@ describe('ReactFragment', () => {
739
}
740
741
ReactNoop.render(<Foo condition={true} />);
738
- expect(Scheduler).toFlushWithoutYielding();
742
+ await waitForAll([]);
743
744
ReactNoop.render(<Foo condition={false} />);
745
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
@@ -751,7 +755,7 @@ describe('ReactFragment', () => {
755
);
756
757
ReactNoop.render(<Foo condition={true} />);
754
- expect(Scheduler).toFlushWithoutYielding();
758
+ await waitForAll([]);
759
760
expect(ops).toEqual([]);
761
expect(ReactNoop).toMatchRenderedOutput(
@@ -762,7 +766,7 @@ describe('ReactFragment', () => {
766
);
767
});
768
765
- it('should not preserve state when switching a nested unkeyed fragment to a passthrough component', function () {
769
+ it('should not preserve state when switching a nested unkeyed fragment to a passthrough component', async function () {
770
const ops = [];
771
772
function Passthrough({children}) {
@@ -796,22 +800,22 @@ describe('ReactFragment', () => {
800
}
801
802
ReactNoop.render(<Foo condition={true} />);
799
- expect(Scheduler).toFlushWithoutYielding();
803
+ await waitForAll([]);
804
805
ReactNoop.render(<Foo condition={false} />);
802
- expect(Scheduler).toFlushWithoutYielding();
806
+ await waitForAll([]);
807
808
expect(ops).toEqual([]);
809
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
810
811
ReactNoop.render(<Foo condition={true} />);
808
- expect(Scheduler).toFlushWithoutYielding();
812
+ await waitForAll([]);
813
814
expect(ops).toEqual([]);
815
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
816
});
817
814
- it('should not preserve state when switching a nested keyed fragment to a passthrough component', function () {
818
+ it('should not preserve state when switching a nested keyed fragment to a passthrough component', async function () {
819
const ops = [];
820
821
function Passthrough({children}) {
@@ -845,22 +849,22 @@ describe('ReactFragment', () => {
849
}
850
851
ReactNoop.render(<Foo condition={true} />);
848
- expect(Scheduler).toFlushWithoutYielding();
852
+ await waitForAll([]);
853
854
ReactNoop.render(<Foo condition={false} />);
851
- expect(Scheduler).toFlushWithoutYielding();
855
+ await waitForAll([]);
856
857
expect(ops).toEqual([]);
858
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
859
860
ReactNoop.render(<Foo condition={true} />);
857
- expect(Scheduler).toFlushWithoutYielding();
861
+ await waitForAll([]);
862
863
expect(ops).toEqual([]);
864
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
865
});
866
863
- it('should not preserve state when switching a nested keyed array to a passthrough component', function () {
867
+ it('should not preserve state when switching a nested keyed array to a passthrough component', async function () {
868
const ops = [];
869
870
function Passthrough({children}) {
@@ -890,22 +894,22 @@ describe('ReactFragment', () => {
894
}
895
896
ReactNoop.render(<Foo condition={true} />);
893
- expect(Scheduler).toFlushWithoutYielding();
897
+ await waitForAll([]);
898
899
ReactNoop.render(<Foo condition={false} />);
896
- expect(Scheduler).toFlushWithoutYielding();
900
+ await waitForAll([]);
901
902
expect(ops).toEqual([]);
903
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
904
905
ReactNoop.render(<Foo condition={true} />);
902
- expect(Scheduler).toFlushWithoutYielding();
906
+ await waitForAll([]);
907
908
expect(ops).toEqual([]);
909
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
910
});
911
908
- it('should preserve state when it does not change positions', function () {
912
+ it('should preserve state when it does not change positions', async function () {
913
const ops = [];
914
915
class Stateful extends React.Component {
@@ -940,8 +944,7 @@ describe('ReactFragment', () => {
944
);
945
946
ReactNoop.render(<Foo condition={false} />);
943
- // The key warning gets deduped because it's in the same component.
944
- expect(Scheduler).toFlushWithoutYielding();
947
+ await waitForAll([]);
948
949
expect(ops).toEqual(['Update Stateful']);
950
expect(ReactNoop).toMatchRenderedOutput(
@@ -952,8 +955,7 @@ describe('ReactFragment', () => {
955
);
956
957
ReactNoop.render(<Foo condition={true} />);
955
- // The key warning gets deduped because it's in the same component.
956
- expect(Scheduler).toFlushWithoutYielding();
958
+ await waitForAll([]);
959
960
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
961
expect(ReactNoop).toMatchRenderedOutput(
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+224
-332
@@ -280,13 +280,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
280
281
// Render empty shell.
282
ReactNoop.render(<Foo />);
283
- expect(Scheduler).toFlushAndYield(['Foo']);
283
+ await waitForAll(['Foo']);
284
285
// The update will suspend.
286
React.startTransition(() => {
287
ReactNoop.render(<Foo renderBar={true} />);
288
});
289
- expect(Scheduler).toFlushAndYield([
289
+ await waitForAll([
290
'Foo',
291
'Bar',
292
// A suspends
@@ -299,8 +299,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
299
300
// Resolve the data
301
await resolveText('A');
302
- // Renders successfully
303
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar', 'A', 'B']);
302
+ await waitForAll(['Foo', 'Bar', 'A', 'B']);
303
expect(ReactNoop).toMatchRenderedOutput(
304
<>
305
<span prop="A" />
@@ -322,7 +321,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
321
</Suspense>
322
</Fragment>,
323
);
325
- expect(Scheduler).toFlushAndYield([
324
+ await waitForAll([
325
'Suspend! [A]',
326
'Loading A...',
327
'Suspend! [B]',
@@ -339,7 +338,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
338
// normal view. The second Suspense should still show the placeholder.
339
await resolveText('A');
340
342
- expect(Scheduler).toFlushAndYield(['A']);
341
+ await waitForAll(['A']);
342
expect(ReactNoop).toMatchRenderedOutput(
343
<>
344
<span prop="A" />
@@ -351,7 +350,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
350
// normal view.
351
await resolveText('B');
352
354
- expect(Scheduler).toFlushAndYield(['B']);
353
+ await waitForAll(['B']);
354
expect(ReactNoop).toMatchRenderedOutput(
355
<>
356
<span prop="A" />
@@ -364,7 +363,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
363
it('continues rendering siblings after suspending', async () => {
364
// A shell is needed. The update cause it to suspend.
365
ReactNoop.render(<Suspense fallback={<Text text="Loading..." />} />);
367
- expect(Scheduler).toFlushAndYield([]);
366
+ await waitForAll([]);
367
// B suspends. Continue rendering the remaining siblings.
368
React.startTransition(() => {
369
ReactNoop.render(
@@ -376,21 +375,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
375
</Suspense>,
376
);
377
});
379
- // B suspends. Continue rendering the remaining siblings.
380
- expect(Scheduler).toFlushAndYield([
381
- 'A',
382
- 'Suspend! [B]',
383
- 'C',
384
- 'D',
385
- 'Loading...',
386
- ]);
378
+ await waitForAll(['A', 'Suspend! [B]', 'C', 'D', 'Loading...']);
379
// Did not commit yet.
380
expect(ReactNoop).toMatchRenderedOutput(null);
381
382
// Wait for data to resolve
383
await resolveText('B');
392
- // Renders successfully
393
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C', 'D']);
384
+ await waitForAll(['A', 'B', 'C', 'D']);
385
expect(ReactNoop).toMatchRenderedOutput(
386
<>
387
<span prop="A" />
@@ -436,18 +427,18 @@ describe('ReactSuspenseWithNoopRenderer', () => {
427
}
428
429
ReactNoop.render(<App />);
439
- expect(Scheduler).toFlushAndYield([]);
430
+ await waitForAll([]);
431
expect(ReactNoop).toMatchRenderedOutput(null);
432
433
React.startTransition(() => {
434
ReactNoop.render(<App renderContent={true} />);
435
});
445
- expect(Scheduler).toFlushAndYield(['Suspend! [Result]', 'Loading...']);
436
+ await waitForAll(['Suspend! [Result]', 'Loading...']);
437
expect(ReactNoop).toMatchRenderedOutput(null);
438
439
await rejectText('Result', new Error('Failed to load: Result'));
440
450
- expect(Scheduler).toFlushAndYield([
441
+ await waitForAll([
442
'Error! [Result]',
443
444
// React retries one more time
@@ -494,12 +485,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
485
}
486
487
ReactNoop.render(<App />);
497
- expect(Scheduler).toFlushAndYield(['Suspend! [Result]', 'Loading...']);
488
+ await waitForAll(['Suspend! [Result]', 'Loading...']);
489
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
490
491
await rejectText('Result', new Error('Failed to load: Result'));
492
502
- expect(Scheduler).toFlushAndYield([
493
+ await waitForAll([
494
'Error! [Result]',
495
496
// React retries one more time
@@ -526,9 +517,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
517
518
// Initial mount
519
ReactNoop.render(<App highPri="A" lowPri="1" />);
529
- expect(Scheduler).toFlushAndYield(['A', 'Suspend! [1]', 'Loading...']);
520
+ await waitForAll(['A', 'Suspend! [1]', 'Loading...']);
521
await resolveText('1');
531
- expect(Scheduler).toFlushAndYield(['A', '1']);
522
+ await waitForAll(['A', '1']);
523
expect(ReactNoop).toMatchRenderedOutput(
524
<>
525
<span prop="A" />
@@ -538,7 +529,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
529
530
// Update the low-pri text
531
ReactNoop.render(<App highPri="A" lowPri="2" />);
541
- expect(Scheduler).toFlushAndYield([
532
+ await waitForAll([
533
'A',
534
// Suspends
535
'Suspend! [2]',
@@ -583,13 +574,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
574
}
575
576
ReactNoop.render(<App showA={false} showB={false} />);
586
- expect(Scheduler).toFlushAndYield([]);
577
+ await waitForAll([]);
578
expect(ReactNoop).toMatchRenderedOutput(null);
579
580
React.startTransition(() => {
581
ReactNoop.render(<App showA={true} showB={false} />);
582
});
592
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
583
+ await waitForAll(['Suspend! [A]', 'Loading...']);
584
expect(ReactNoop).toMatchRenderedOutput(null);
585
586
// Advance React's virtual time by enough to fall into a new async bucket,
@@ -598,11 +589,11 @@ describe('ReactSuspenseWithNoopRenderer', () => {
589
React.startTransition(() => {
590
ReactNoop.render(<App showA={true} showB={true} />);
591
});
601
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'B', 'Loading...']);
592
+ await waitForAll(['Suspend! [A]', 'B', 'Loading...']);
593
expect(ReactNoop).toMatchRenderedOutput(null);
594
595
await resolveText('A');
605
- expect(Scheduler).toFlushAndYield(['A', 'B']);
596
+ await waitForAll(['A', 'B']);
597
expect(ReactNoop).toMatchRenderedOutput(
598
<>
599
<span prop="A" />
@@ -632,7 +623,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
623
ReactNoop.render(<App hide={true} />);
624
});
625
635
- expect(Scheduler).toFlushAndYield([
626
+ await waitForAll([
627
// The first update suspends
628
'Suspend! [Async]',
629
// but we have another pending update that we can work on
@@ -675,7 +666,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
666
root.render(<App step={0} shouldSuspend={false} />);
667
});
668
await advanceTimers(1000);
678
- expect(Scheduler).toHaveYielded(['Sibling', 'Step 0']);
669
+ assertLog(['Sibling', 'Step 0']);
670
671
// Schedule an update at several distinct expiration times
672
await act(async () => {
@@ -683,27 +674,27 @@ describe('ReactSuspenseWithNoopRenderer', () => {
674
root.render(<App step={1} shouldSuspend={true} />);
675
});
676
Scheduler.unstable_advanceTime(1000);
686
- expect(Scheduler).toFlushAndYieldThrough(['Sibling']);
677
+ await waitFor(['Sibling']);
678
interrupt();
679
680
React.startTransition(() => {
681
root.render(<App step={2} shouldSuspend={true} />);
682
});
683
Scheduler.unstable_advanceTime(1000);
693
- expect(Scheduler).toFlushAndYieldThrough(['Sibling']);
684
+ await waitFor(['Sibling']);
685
interrupt();
686
687
React.startTransition(() => {
688
root.render(<App step={3} shouldSuspend={true} />);
689
});
690
Scheduler.unstable_advanceTime(1000);
700
- expect(Scheduler).toFlushAndYieldThrough(['Sibling']);
691
+ await waitFor(['Sibling']);
692
interrupt();
693
694
root.render(<App step={4} shouldSuspend={false} />);
695
});
696
706
- expect(Scheduler).toHaveYielded(['Sibling', 'Step 4']);
697
+ assertLog(['Sibling', 'Step 4']);
698
});
699
700
// @gate enableLegacyCache
@@ -713,7 +704,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
704
<Suspense fallback={<Text text="Loading..." />} />
705
</Fragment>,
706
);
716
- expect(Scheduler).toFlushAndYield([]);
707
+ await waitForAll([]);
708
709
ReactNoop.render(
710
<Fragment>
@@ -724,7 +715,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
715
</Fragment>,
716
);
717
727
- expect(Scheduler).toFlushAndYield([
718
+ await waitForAll([
719
// The async child suspends
720
'Suspend! [Async]',
721
// Render the placeholder
@@ -739,9 +730,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
730
// the update.
731
ReactNoop.expire(10000);
732
await advanceTimers(10000);
742
- // No additional rendering work is required, since we already prepared
743
- // the placeholder.
744
- expect(Scheduler).toHaveYielded([]);
733
+ assertLog([]);
734
// Should have committed the placeholder.
735
expect(ReactNoop).toMatchRenderedOutput(
736
<>
@@ -752,7 +741,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
741
742
// Once the promise resolves, we render the suspended view
743
await resolveText('Async');
755
- expect(Scheduler).toFlushAndYield(['Async']);
744
+ await waitForAll(['Async']);
745
expect(ReactNoop).toMatchRenderedOutput(
746
<>
747
<span prop="Async" />
@@ -778,7 +767,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
767
</Fragment>,
768
);
769
781
- expect(Scheduler).toFlushAndYield([
770
+ await waitForAll([
771
'Sync',
772
// The async content suspends
773
'Suspend! [Outer content]',
@@ -796,7 +785,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
785
786
// Resolve the outer promise.
787
await resolveText('Outer content');
799
- expect(Scheduler).toFlushAndYield([
788
+ await waitForAll([
789
'Outer content',
790
'Suspend! [Inner content]',
791
'Loading inner...',
@@ -824,7 +813,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
813
814
// Finally, flush the inner promise. We should see the complete screen.
815
await resolveText('Inner content');
827
- expect(Scheduler).toFlushAndYield(['Inner content']);
816
+ await waitForAll(['Inner content']);
817
expect(ReactNoop).toMatchRenderedOutput(
818
<>
819
<span prop="Sync" />
@@ -848,7 +837,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
837
</Fragment>,
838
),
839
);
851
- expect(Scheduler).toHaveYielded([
840
+ assertLog([
841
// The async child suspends
842
'Suspend! [Async]',
843
// We immediately render the fallback UI
@@ -866,7 +855,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
855
856
// Once the promise resolves, we render the suspended view
857
await resolveText('Async');
869
- expect(Scheduler).toFlushAndYield(['Async']);
858
+ await waitForAll(['Async']);
859
expect(ReactNoop).toMatchRenderedOutput(
860
<>
861
<span prop="Async" />
@@ -889,7 +878,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
878
</Fragment>,
879
),
880
);
892
- expect(Scheduler).toHaveYielded([
881
+ assertLog([
882
'Suspend! [Async]',
883
'Suspend! [Loading (inner)...]',
884
'Sync',
@@ -906,7 +895,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
895
<Suspense fallback={<Text text="Loading..." />} />
896
</Fragment>,
897
);
909
- expect(Scheduler).toFlushAndYield([]);
898
+ await waitForAll([]);
899
900
ReactNoop.render(
901
<Fragment>
@@ -917,7 +906,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
906
</Fragment>,
907
);
908
920
- expect(Scheduler).toFlushAndYield([
909
+ await waitForAll([
910
// The async child suspends
911
'Suspend! [Async]',
912
'Loading...',
@@ -932,7 +921,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
921
// expiration time.
922
ReactNoop.expire(2000);
923
await advanceTimers(2000);
935
- expect(Scheduler).toFlushWithoutYielding();
924
+ await waitForAll([]);
925
expect(ReactNoop).toMatchRenderedOutput(
926
<>
927
<span prop="Loading..." />
@@ -942,7 +931,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
931
932
// Once the promise resolves, we render the suspended view
933
await resolveText('Async');
945
- expect(Scheduler).toFlushAndYield(['Async']);
934
+ await waitForAll(['Async']);
935
expect(ReactNoop).toMatchRenderedOutput(
936
<>
937
<span prop="Async" />
@@ -958,7 +947,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
947
<Suspense fallback={<Text text="Loading..." />} />
948
</Fragment>,
949
);
961
- expect(Scheduler).toFlushAndYield([]);
950
+ await waitForAll([]);
951
952
React.startTransition(() => {
953
ReactNoop.render(
@@ -971,7 +960,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
960
);
961
});
962
974
- expect(Scheduler).toFlushAndYield([
963
+ await waitForAll([
964
// The async child suspends
965
'Suspend! [Async]',
966
'Loading...',
@@ -987,13 +976,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
976
await advanceTimers(2000);
977
expect(ReactNoop).toMatchRenderedOutput(null);
978
990
- // Even flushing won't yield a fallback in a transition.
991
- expect(Scheduler).toFlushWithoutYielding();
979
+ await waitForAll([]);
980
expect(ReactNoop).toMatchRenderedOutput(null);
981
982
// Once the promise resolves, we render the suspended view
983
await resolveText('Async');
996
- expect(Scheduler).toFlushAndYield(['Async', 'Sync']);
984
+ await waitForAll(['Async', 'Sync']);
985
expect(ReactNoop).toMatchRenderedOutput(
986
<>
987
<span prop="Async" />
@@ -1010,7 +998,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
998
<Suspense fallback={<Text text="Loading..." />} />
999
</>,
1000
);
1013
- expect(Scheduler).toFlushAndYield([]);
1001
+ await waitForAll([]);
1002
expect(root).toMatchRenderedOutput(null);
1003
React.startTransition(() => {
1004
root.render(
@@ -1022,13 +1010,11 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1010
</>,
1011
);
1012
});
1025
- expect(Scheduler).toFlushAndYieldThrough(['Suspend! [Async]', 'Sibling']);
1013
+ await waitFor(['Suspend! [Async]', 'Sibling']);
1014
1015
await resolveText('Async');
1016
1029
- // Because we're already showing a fallback, interrupt the current render
1030
- // and restart immediately.
1031
- expect(Scheduler).toFlushAndYield(['Async', 'Sibling']);
1017
+ await waitForAll(['Async', 'Sibling']);
1018
expect(root).toMatchRenderedOutput(
1019
<>
1020
<span prop="Async" />
@@ -1063,17 +1049,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1049
<AsyncText text="B" />
1050
</Suspense>,
1051
);
1066
- expect(Scheduler).toFlushAndYield([
1067
- 'Suspend! [A]',
1068
- 'Suspend! [B]',
1069
- 'Loading...',
1070
- ]);
1052
+ await waitForAll(['Suspend! [A]', 'Suspend! [B]', 'Loading...']);
1053
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
1054
1055
await resolveText('A');
1056
await resolveText('B');
1057
1076
- expect(Scheduler).toFlushAndYield(['A', 'B']);
1058
+ await waitForAll(['A', 'B']);
1059
expect(ReactNoop).toMatchRenderedOutput(
1060
<>
1061
<span prop="A" />
@@ -1085,7 +1067,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1067
// @gate enableLegacyCache
1068
it('can resume rendering earlier than a timeout', async () => {
1069
ReactNoop.render(<Suspense fallback={<Text text="Loading..." />} />);
1088
- expect(Scheduler).toFlushAndYield([]);
1070
+ await waitForAll([]);
1071
1072
React.startTransition(() => {
1073
ReactNoop.render(
@@ -1094,13 +1076,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1076
</Suspense>,
1077
);
1078
});
1097
- expect(Scheduler).toFlushAndYield(['Suspend! [Async]', 'Loading...']);
1079
+ await waitForAll(['Suspend! [Async]', 'Loading...']);
1080
expect(ReactNoop).toMatchRenderedOutput(null);
1081
1082
// Resolve the promise
1083
await resolveText('Async');
1102
- // We can now resume rendering
1103
- expect(Scheduler).toFlushAndYield(['Async']);
1084
+ await waitForAll(['Async']);
1085
expect(ReactNoop).toMatchRenderedOutput(<span prop="Async" />);
1086
});
1087
@@ -1121,37 +1102,34 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1102
// First mount without suspending. This ensures we already have content
1103
// showing so that subsequent updates will suspend.
1104
ReactNoop.render(<App text="S" />);
1124
- expect(Scheduler).toFlushAndYield(['S']);
1105
+ await waitForAll(['S']);
1106
1107
// Schedule an update, and suspend for up to 5 seconds.
1108
React.startTransition(() => ReactNoop.render(<App text="A" />));
1128
- // The update should suspend.
1129
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
1109
+ await waitForAll(['Suspend! [A]', 'Loading...']);
1110
expect(ReactNoop).toMatchRenderedOutput(<span prop="S" />);
1111
1112
// Advance time until right before it expires.
1113
await advanceTimers(4999);
1114
ReactNoop.expire(4999);
1135
- expect(Scheduler).toFlushWithoutYielding();
1115
+ await waitForAll([]);
1116
expect(ReactNoop).toMatchRenderedOutput(<span prop="S" />);
1117
1118
// Schedule another low priority update.
1119
React.startTransition(() => ReactNoop.render(<App text="B" />));
1140
- // This update should also suspend.
1141
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
1120
+ await waitForAll(['Suspend! [B]', 'Loading...']);
1121
expect(ReactNoop).toMatchRenderedOutput(<span prop="S" />);
1122
1123
// Schedule a regular update. Its expiration time will fall between
1124
// the expiration times of the previous two updates.
1125
ReactNoop.render(<App text="C" />);
1147
- expect(Scheduler).toFlushAndYield(['C']);
1126
+ await waitForAll(['C']);
1127
expect(ReactNoop).toMatchRenderedOutput(<span prop="C" />);
1128
1129
// Flush the remaining work.
1130
await resolveText('A');
1131
await resolveText('B');
1153
- // Nothing else to render.
1154
- expect(Scheduler).toFlushWithoutYielding();
1132
+ await waitForAll([]);
1133
expect(ReactNoop).toMatchRenderedOutput(<span prop="C" />);
1134
});
1135
@@ -1188,17 +1166,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1166
jest.advanceTimersByTime(1000);
1167
ReactNoop.render(<Foo text="goodbye" />);
1168
1191
- expect(Scheduler).toFlushAndYield([
1192
- 'Suspend! [goodbye]',
1193
- 'Loading...',
1194
- 'Commit: goodbye',
1195
- ]);
1169
+ await waitForAll(['Suspend! [goodbye]', 'Loading...', 'Commit: goodbye']);
1170
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
1171
1172
await resolveText('goodbye');
1173
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
1174
1201
- expect(Scheduler).toFlushAndYield(['goodbye']);
1175
+ await waitForAll(['goodbye']);
1176
expect(ReactNoop).toMatchRenderedOutput(<span prop="goodbye" />);
1177
});
1178
@@ -1223,18 +1197,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1197
}
1198
1199
ReactNoop.render(<App />);
1226
- expect(Scheduler).toFlushAndYield([
1227
- 'Suspend! [A]',
1228
- 'Suspend! [B]',
1229
- 'Suspend! [C]',
1230
- ]);
1200
+ await waitForAll(['Suspend! [A]', 'Suspend! [B]', 'Suspend! [C]']);
1201
expect(ReactNoop).toMatchRenderedOutput('Loading...');
1202
1203
await resolveText('A');
1204
await resolveText('B');
1205
await resolveText('C');
1206
1237
- expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
1207
+ await waitForAll(['A', 'B', 'C']);
1208
expect(ReactNoop).toMatchRenderedOutput(
1209
<>
1210
<span prop="A" />
@@ -1257,14 +1227,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1227
1228
// Times out immediately, ignoring the specified threshold.
1229
ReactNoop.renderLegacySyncRoot(<App />);
1260
- expect(Scheduler).toHaveYielded(['Suspend! [Result]', 'Loading...']);
1230
+ assertLog(['Suspend! [Result]', 'Loading...']);
1231
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
1232
1233
await act(async () => {
1234
resolveText('Result');
1235
});
1236
1267
- expect(Scheduler).toHaveYielded(['Result']);
1237
+ assertLog(['Result']);
1238
expect(ReactNoop).toMatchRenderedOutput(<span prop="Result" />);
1239
});
1240
@@ -1300,7 +1270,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1270
// Initial mount.
1271
await seedNextTextCache('Step: 1');
1272
ReactNoop.renderLegacySyncRoot(<App />);
1303
- expect(Scheduler).toHaveYielded(['Step: 1', 'Sibling']);
1273
+ assertLog(['Step: 1', 'Sibling']);
1274
expect(ReactNoop).toMatchRenderedOutput(
1275
<>
1276
<span prop="Step: 1" />
@@ -1333,7 +1303,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1303
await act(async () => {
1304
resolveText('Step: 2');
1305
});
1336
- expect(Scheduler).toHaveYielded(['Step: 2']);
1306
+ assertLog(['Step: 2']);
1307
expect(ReactNoop).toMatchRenderedOutput(
1308
<>
1309
<span prop="Step: 2" />
@@ -1381,7 +1351,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1351
ReactNoop.renderLegacySyncRoot(<App />, () =>
1352
Scheduler.unstable_yieldValue('Commit root'),
1353
);
1384
- expect(Scheduler).toHaveYielded([
1354
+ assertLog([
1355
'A',
1356
'Suspend! [B]',
1357
'C',
@@ -1407,7 +1377,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1377
resolveText('B');
1378
});
1379
1410
- expect(Scheduler).toHaveYielded(['B']);
1380
+ assertLog(['B']);
1381
expect(ReactNoop).toMatchRenderedOutput(
1382
<>
1383
<span prop="A" />
@@ -1442,22 +1412,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1412
</Suspense>,
1413
);
1414
1445
- expect(Scheduler).toHaveYielded([
1446
- 'constructor',
1447
- 'Suspend! [Hi]',
1448
- 'Loading...',
1449
- ]);
1415
+ assertLog(['constructor', 'Suspend! [Hi]', 'Loading...']);
1416
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
1417
1418
await act(async () => {
1419
resolveText('Hi');
1420
});
1421
1456
- expect(Scheduler).toHaveYielded([
1457
- 'constructor',
1458
- 'Hi',
1459
- 'componentDidMount',
1460
- ]);
1422
+ assertLog(['constructor', 'Hi', 'componentDidMount']);
1423
expect(ReactNoop).toMatchRenderedOutput(<span prop="Hi" />);
1424
});
1425
@@ -1489,7 +1451,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1451
1452
ReactNoop.renderLegacySyncRoot(<Demo />);
1453
1492
- expect(Scheduler).toHaveYielded([
1454
+ assertLog([
1455
'Suspend! [Hi]',
1456
'Loading...',
1457
// Re-render due to lifecycle update
@@ -1499,7 +1461,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1461
await act(async () => {
1462
resolveText('Hi');
1463
});
1502
- expect(Scheduler).toHaveYielded(['Hi']);
1464
+ assertLog(['Hi']);
1465
expect(ReactNoop).toMatchRenderedOutput(<span prop="Hi" />);
1466
});
1467
@@ -1532,7 +1494,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1494
1495
ReactNoop.renderLegacySyncRoot(<App middleText="B" />);
1496
1535
- expect(Scheduler).toHaveYielded([
1497
+ assertLog([
1498
'Suspend! [Hi]',
1499
'Loading...',
1500
// The child should have already been hidden
@@ -1545,7 +1507,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1507
await act(async () => {
1508
resolveText('Hi');
1509
});
1548
- expect(Scheduler).toHaveYielded(['Hi']);
1510
+ assertLog(['Hi']);
1511
});
1512
} else {
1513
// @gate enableLegacyCache
@@ -1578,7 +1540,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1540
1541
ReactNoop.renderLegacySyncRoot(<App middleText="B" />);
1542
1581
- expect(Scheduler).toHaveYielded([
1543
+ assertLog([
1544
'Suspend! [Hi]',
1545
'Loading...',
1546
// The child should have already been hidden
@@ -1589,7 +1551,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1551
resolveText('Hi');
1552
});
1553
1592
- expect(Scheduler).toHaveYielded(['Hi']);
1554
+ assertLog(['Hi']);
1555
});
1556
}
1557
@@ -1622,7 +1584,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1584
</ErrorBoundary>,
1585
);
1586
1625
- expect(Scheduler).toHaveYielded(['Suspend! [Async]']);
1587
+ assertLog(['Suspend! [Async]']);
1588
expect(ReactNoop).toMatchRenderedOutput(
1589
'Caught an error: Error in host config.',
1590
);
@@ -1661,7 +1623,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1623
await act(async () => {
1624
root.render(<App />);
1625
});
1664
- expect(Scheduler).toHaveYielded(['Mount']);
1626
+ assertLog(['Mount']);
1627
expect(root).toMatchRenderedOutput('Child');
1628
1629
// Suspend the child. This puts it into an inconsistent state.
@@ -1674,7 +1636,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1636
await act(async () => {
1637
root.render(null);
1638
});
1677
- expect(Scheduler).toHaveYielded(['Unmount']);
1639
+ assertLog(['Unmount']);
1640
});
1641
});
1642
@@ -1726,7 +1688,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1688
ReactNoop.renderLegacySyncRoot(<App />, () =>
1689
Scheduler.unstable_yieldValue('Commit root'),
1690
);
1729
- expect(Scheduler).toHaveYielded([
1691
+ assertLog([
1692
'A',
1693
'Suspend! [B]',
1694
'C',
@@ -1802,7 +1764,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1764
ReactNoop.renderLegacySyncRoot(<App text="B" />, () =>
1765
Scheduler.unstable_yieldValue('Commit root'),
1766
);
1805
- expect(Scheduler).toHaveYielded([
1767
+ assertLog([
1768
'A',
1769
'Suspend! [B]',
1770
'C',
@@ -1816,8 +1778,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1778
'Commit root',
1779
]);
1780
1819
- // Flush passive effects.
1820
- expect(Scheduler).toFlushAndYield([
1781
+ await waitForAll([
1782
'Effect [A]',
1783
// B's effect should not fire because it suspended
1784
// 'Effect [B]',
@@ -1837,7 +1798,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1798
resolveText('B');
1799
});
1800
1840
- expect(Scheduler).toHaveYielded([
1801
+ assertLog([
1802
'B',
1803
'Destroy Layout Effect [Loading...]',
1804
'Layout Effect [B]',
@@ -1850,7 +1811,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1811
Scheduler.unstable_yieldValue('Commit root'),
1812
);
1813
1853
- expect(Scheduler).toHaveYielded([
1814
+ assertLog([
1815
'A',
1816
'Suspend! [B2]',
1817
'C',
@@ -1862,8 +1823,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1823
'Commit root',
1824
]);
1825
1865
- // Flush passive effects.
1866
- expect(Scheduler).toFlushAndYield([
1826
+ await waitForAll([
1827
// B2's effect should not fire because it suspended
1828
// 'Effect [B2]',
1829
'Effect [Loading...]',
@@ -1873,7 +1833,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1833
resolveText('B2');
1834
});
1835
1876
- expect(Scheduler).toHaveYielded([
1836
+ assertLog([
1837
'B2',
1838
'Destroy Layout Effect [Loading...]',
1839
'Destroy Layout Effect [B]',
@@ -1896,19 +1856,18 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1856
}
1857
1858
ReactNoop.render(<Foo />);
1899
- expect(Scheduler).toFlushAndYield(['Foo']);
1859
+ await waitForAll(['Foo']);
1860
1861
React.startTransition(() => {
1862
ReactNoop.render(<Foo renderContent={true} />);
1863
});
1864
Scheduler.unstable_advanceTime(100);
1865
await advanceTimers(100);
1906
- // Start rendering
1907
- expect(Scheduler).toFlushAndYieldThrough(['Foo']);
1866
+ await waitFor(['Foo']);
1867
// For some reason it took a long time to render Foo.
1868
Scheduler.unstable_advanceTime(1250);
1869
await advanceTimers(1250);
1911
- expect(Scheduler).toFlushAndYield([
1870
+ await waitForAll([
1871
// A suspends
1872
'Suspend! [A]',
1873
'Loading...',
@@ -1919,24 +1878,19 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1878
// Flush some of the time
1879
Scheduler.unstable_advanceTime(450);
1880
await advanceTimers(450);
1922
- // Because we've already been waiting for so long we can
1923
- // wait a bit longer. Still nothing...
1924
- expect(Scheduler).toFlushWithoutYielding();
1881
+ await waitForAll([]);
1882
expect(ReactNoop).toMatchRenderedOutput(null);
1883
1884
// Eventually we'll show the fallback.
1885
Scheduler.unstable_advanceTime(500);
1886
await advanceTimers(500);
1930
- // No need to rerender.
1931
- expect(Scheduler).toFlushWithoutYielding();
1887
+ await waitForAll([]);
1888
// Since this is a transition, we never fallback.
1889
expect(ReactNoop).toMatchRenderedOutput(null);
1890
1891
// Flush the promise completely
1892
await resolveText('A');
1937
- // Renders successfully
1938
- // TODO: Why does this render Foo
1939
- expect(Scheduler).toFlushAndYield(['Foo', 'A']);
1893
+ await waitForAll(['Foo', 'A']);
1894
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
1895
});
1896
@@ -1955,8 +1909,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1909
}
1910
1911
ReactNoop.render(<Foo />);
1958
- // Start rendering
1959
- expect(Scheduler).toFlushAndYield([
1912
+ await waitForAll([
1913
'Foo',
1914
// A suspends
1915
'Suspend! [A]',
@@ -1972,8 +1925,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1925
Scheduler.unstable_advanceTime(5000);
1926
await advanceTimers(5000);
1927
1975
- // Retry with the new content.
1976
- expect(Scheduler).toFlushAndYield([
1928
+ await waitForAll([
1929
'A',
1930
// B still suspends
1931
'Suspend! [B]',
@@ -1991,8 +1943,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1943
1944
// Flush the last promise completely
1945
await resolveText('B');
1994
- // Renders successfully
1995
- expect(Scheduler).toFlushAndYield(['B']);
1946
+ await waitForAll(['B']);
1947
expect(ReactNoop).toMatchRenderedOutput(
1948
<>
1949
<span prop="A" />
@@ -2016,8 +1967,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1967
}
1968
1969
ReactNoop.render(<Foo />);
2019
- // Start rendering
2020
- expect(Scheduler).toFlushAndYield([
1970
+ await waitForAll([
1971
'Foo',
1972
// A suspends
1973
'Suspend! [A]',
@@ -2030,8 +1980,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1980
1981
await resolveText('A');
1982
2033
- // Retry with the new content.
2034
- expect(Scheduler).toFlushAndYield([
1983
+ await waitForAll([
1984
'A',
1985
// B still suspends
1986
'Suspend! [B]',
@@ -2046,8 +1995,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1995
// Before we commit another Promise resolves.
1996
// We're still showing the first loading state.
1997
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
2049
- // Restart and render the complete content.
2050
- expect(Scheduler).toFlushAndYield(['A', 'B']);
1998
+ await waitForAll(['A', 'B']);
1999
expect(ReactNoop).toMatchRenderedOutput(
2000
<>
2001
<span prop="A" />
@@ -2068,18 +2016,18 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2016
}
2017
2018
ReactNoop.render(<Foo />);
2071
- expect(Scheduler).toFlushAndYield(['Foo']);
2019
+ await waitForAll(['Foo']);
2020
2021
React.startTransition(() => {
2022
ReactNoop.render(<Foo renderContent={true} />);
2023
});
2076
- expect(Scheduler).toFlushAndYieldThrough(['Foo']);
2024
+ await waitFor(['Foo']);
2025
2026
// Advance some time.
2027
Scheduler.unstable_advanceTime(100);
2028
await advanceTimers(100);
2029
2082
- expect(Scheduler).toFlushAndYield([
2030
+ await waitForAll([
2031
// A suspends
2032
'Suspend! [A]',
2033
'Loading...',
@@ -2092,11 +2040,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2040
Scheduler.unstable_advanceTime(500);
2041
jest.advanceTimersByTime(500);
2042
2095
- // We should have already shown the fallback.
2096
- // When we wrote this test, we inferred the start time of high priority
2097
- // updates as way earlier in the past. This test ensures that we don't
2098
- // use this assumption to add a very long JND.
2099
- expect(Scheduler).toFlushWithoutYielding();
2043
+ await waitForAll([]);
2044
// Transitions never fallback.
2045
expect(ReactNoop).toMatchRenderedOutput(null);
2046
});
@@ -2173,14 +2117,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2117
ReactNoop.render(<App />);
2118
});
2119
2176
- expect(Scheduler).toHaveYielded(['Suspend! [A]']);
2120
+ assertLog(['Suspend! [A]']);
2121
expect(ReactNoop).toMatchRenderedOutput('Loading...');
2122
2123
act(() => {
2124
ReactNoop.flushSync(() => showB());
2125
});
2126
2183
- expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Suspend! [B]']);
2127
+ assertLog(['Suspend! [A]', 'Suspend! [B]']);
2128
});
2129
2130
// TODO: flip to "warns" when this is implemented again.
@@ -2236,7 +2180,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2180
// also make sure lowpriority is okay
2181
await act(async () => show(true));
2182
2239
- expect(Scheduler).toHaveYielded(['Suspend! [A]']);
2183
+ assertLog(['Suspend! [A]']);
2184
await resolveText('A');
2185
2186
expect(ReactNoop).toMatchRenderedOutput('Loading...');
@@ -2262,7 +2206,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2206
// also make sure lowpriority is okay
2207
await act(async () => _setShow(true));
2208
2265
- expect(Scheduler).toHaveYielded(['Suspend! [A]']);
2209
+ assertLog(['Suspend! [A]']);
2210
await resolveText('A');
2211
2212
expect(ReactNoop).toMatchRenderedOutput('Loading...');
@@ -2286,17 +2230,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2230
}
2231
2232
ReactNoop.render(<Foo />);
2289
- expect(Scheduler).toFlushAndYield([
2290
- 'Foo',
2291
- 'Suspend! [A]',
2292
- 'B',
2293
- 'Initial load...',
2294
- ]);
2233
+ await waitForAll(['Foo', 'Suspend! [A]', 'B', 'Initial load...']);
2234
expect(ReactNoop).toMatchRenderedOutput(<span prop="Initial load..." />);
2235
2236
// Eventually we resolve and show the data.
2237
await resolveText('A');
2299
- expect(Scheduler).toFlushAndYield(['A', 'B']);
2238
+ await waitForAll(['A', 'B']);
2239
expect(ReactNoop).toMatchRenderedOutput(
2240
<>
2241
<span prop="A" />
@@ -2306,13 +2245,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2245
2246
// Update to show C
2247
ReactNoop.render(<Foo showC={true} />);
2309
- expect(Scheduler).toFlushAndYield([
2310
- 'Foo',
2311
- 'A',
2312
- 'Suspend! [C]',
2313
- 'Updating...',
2314
- 'B',
2315
- ]);
2248
+ await waitForAll(['Foo', 'A', 'Suspend! [C]', 'Updating...', 'B']);
2249
// Flush to skip suspended time.
2250
Scheduler.unstable_advanceTime(600);
2251
await advanceTimers(600);
@@ -2328,7 +2261,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2261
2262
// Later we load the data.
2263
await resolveText('C');
2331
- expect(Scheduler).toFlushAndYield(['A', 'C']);
2264
+ await waitForAll(['A', 'C']);
2265
expect(ReactNoop).toMatchRenderedOutput(
2266
<>
2267
<span prop="A" />
@@ -2354,7 +2287,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2287
}
2288
2289
ReactNoop.render(<Foo />);
2357
- expect(Scheduler).toFlushAndYield([
2290
+ await waitForAll([
2291
'Foo',
2292
'Suspend! [A]',
2293
'B',
@@ -2364,7 +2297,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2297
2298
// Eventually we resolve and show the data.
2299
await resolveText('A');
2367
- expect(Scheduler).toFlushAndYield(['A']);
2300
+ await waitForAll(['A']);
2301
expect(ReactNoop).toMatchRenderedOutput(
2302
<>
2303
<span prop="A" />
@@ -2374,7 +2307,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2307
2308
// Update to show C
2309
ReactNoop.render(<Foo showC={true} />);
2377
- expect(Scheduler).toFlushAndYield([
2310
+ await waitForAll([
2311
'Foo',
2312
'A',
2313
'Suspend! [C]',
@@ -2393,7 +2326,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2326
2327
// Later we load the data.
2328
await resolveText('C');
2396
- expect(Scheduler).toFlushAndYield(['A', 'C']);
2329
+ await waitForAll(['A', 'C']);
2330
expect(ReactNoop).toMatchRenderedOutput(
2331
<>
2332
<span prop="A" />
@@ -2422,12 +2355,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2355
}
2356
2357
ReactNoop.render(<Foo />);
2425
- expect(Scheduler).toFlushAndYield([
2426
- 'Foo',
2427
- 'A',
2428
- 'Suspend! [B]',
2429
- 'Loading B...',
2430
- ]);
2358
+ await waitForAll(['Foo', 'A', 'Suspend! [B]', 'Loading B...']);
2359
// Flush to skip suspended time.
2360
Scheduler.unstable_advanceTime(600);
2361
await advanceTimers(600);
@@ -2463,19 +2391,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2391
}
2392
2393
ReactNoop.render(<Foo />);
2466
- expect(Scheduler).toFlushAndYield(['Foo', 'A']);
2394
+ await waitForAll(['Foo', 'A']);
2395
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2396
2397
React.startTransition(() => {
2398
ReactNoop.render(<Foo showB={true} />);
2399
});
2400
2473
- expect(Scheduler).toFlushAndYield([
2474
- 'Foo',
2475
- 'A',
2476
- 'Suspend! [B]',
2477
- 'Loading B...',
2478
- ]);
2401
+ await waitForAll(['Foo', 'A', 'Suspend! [B]', 'Loading B...']);
2402
// Still suspended.
2403
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2404
@@ -2506,14 +2429,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2429
}
2430
2431
ReactNoop.render(<Foo />);
2509
- expect(Scheduler).toFlushAndYield(['Foo', 'A']);
2432
+ await waitForAll(['Foo', 'A']);
2433
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2434
2435
React.startTransition(() => {
2436
ReactNoop.render(<Foo showB={true} />);
2437
});
2438
2516
- expect(Scheduler).toFlushAndYield([
2439
+ await waitForAll([
2440
'Foo',
2441
'A',
2442
'Suspend! [B]',
@@ -2543,7 +2466,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2466
}
2467
2468
ReactNoop.render(<Foo />);
2546
- expect(Scheduler).toFlushAndYield([]);
2469
+ await waitForAll([]);
2470
2471
ReactNoop.render(<Foo renderContent={1} />);
2472
@@ -2552,14 +2475,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2475
Scheduler.unstable_advanceTime(1500);
2476
await advanceTimers(1500);
2477
2555
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading A...']);
2478
+ await waitForAll(['Suspend! [A]', 'Loading A...']);
2479
// We're still suspended.
2480
expect(ReactNoop).toMatchRenderedOutput(null);
2481
2482
// Schedule an update at idle pri.
2483
ReactNoop.idleUpdates(() => ReactNoop.render(<Foo renderContent={2} />));
2561
- // We won't even work on Idle priority.
2562
- expect(Scheduler).toFlushAndYield([]);
2484
+ await waitForAll([]);
2485
2486
// We're still suspended.
2487
expect(ReactNoop).toMatchRenderedOutput(null);
@@ -2592,7 +2514,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2514
// Initial render.
2515
React.startTransition(() => ReactNoop.render(<App page="A" />));
2516
2595
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2517
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2518
// Only a short time is needed to unsuspend the initial loading state.
2519
Scheduler.unstable_advanceTime(400);
2520
await advanceTimers(400);
@@ -2600,13 +2522,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2522
2523
// Later we load the data.
2524
await resolveText('A');
2603
- expect(Scheduler).toFlushAndYield(['A']);
2525
+ await waitForAll(['A']);
2526
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2527
2528
// Start transition.
2529
React.startTransition(() => ReactNoop.render(<App page="B" />));
2530
2609
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2531
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2532
Scheduler.unstable_advanceTime(100000);
2533
await advanceTimers(100000);
2534
// Even after lots of time has passed, we have still not yet flushed the
@@ -2614,7 +2536,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2536
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2537
// Later we load the data.
2538
await resolveText('B');
2617
- expect(Scheduler).toFlushAndYield(['B']);
2539
+ await waitForAll(['B']);
2540
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2541
});
2542
@@ -2635,13 +2557,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2557
}
2558
2559
ReactNoop.render(<App />);
2638
- expect(Scheduler).toFlushAndYield([]);
2560
+ await waitForAll([]);
2561
2562
// Initial render.
2563
await act(async () => {
2564
React.startTransition(() => transitionToPage('A'));
2565
2644
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2566
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2567
// Only a short time is needed to unsuspend the initial loading state.
2568
Scheduler.unstable_advanceTime(400);
2569
await advanceTimers(400);
@@ -2650,14 +2572,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2572
2573
// Later we load the data.
2574
await resolveText('A');
2653
- expect(Scheduler).toFlushAndYield(['A']);
2575
+ await waitForAll(['A']);
2576
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2577
2578
// Start transition.
2579
await act(async () => {
2580
React.startTransition(() => transitionToPage('B'));
2581
2660
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2582
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2583
Scheduler.unstable_advanceTime(100000);
2584
await advanceTimers(100000);
2585
// Even after lots of time has passed, we have still not yet flushed the
@@ -2666,7 +2588,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2588
});
2589
// Later we load the data.
2590
await resolveText('B');
2669
- expect(Scheduler).toFlushAndYield(['B']);
2591
+ await waitForAll(['B']);
2592
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2593
});
2594
@@ -2690,13 +2612,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2612
}
2613
2614
ReactNoop.render(<App />);
2693
- expect(Scheduler).toFlushAndYield([]);
2615
+ await waitForAll([]);
2616
2617
// Initial render.
2618
await act(async () => {
2619
React.startTransition(() => transitionToPage('A'));
2620
2699
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2621
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2622
// Only a short time is needed to unsuspend the initial loading state.
2623
Scheduler.unstable_advanceTime(400);
2624
await advanceTimers(400);
@@ -2705,14 +2627,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2627
2628
// Later we load the data.
2629
await resolveText('A');
2708
- expect(Scheduler).toFlushAndYield(['A']);
2630
+ await waitForAll(['A']);
2631
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2632
2633
// Start transition.
2634
await act(async () => {
2635
React.startTransition(() => transitionToPage('B'));
2636
2715
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2637
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2638
Scheduler.unstable_advanceTime(100000);
2639
await advanceTimers(100000);
2640
// Even after lots of time has passed, we have still not yet flushed the
@@ -2721,7 +2643,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2643
});
2644
// Later we load the data.
2645
await resolveText('B');
2724
- expect(Scheduler).toFlushAndYield(['B']);
2646
+ await waitForAll(['B']);
2647
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2648
});
2649
});
@@ -2740,7 +2662,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2662
// Initial render.
2663
React.startTransition(() => ReactNoop.render(<App page="A" />));
2664
2743
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2665
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2666
// Only a short time is needed to unsuspend the initial loading state.
2667
Scheduler.unstable_advanceTime(400);
2668
await advanceTimers(400);
@@ -2748,13 +2670,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2670
2671
// Later we load the data.
2672
await resolveText('A');
2751
- expect(Scheduler).toFlushAndYield(['A']);
2673
+ await waitForAll(['A']);
2674
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2675
2676
// Start transition.
2677
React.startTransition(() => ReactNoop.render(<App page="B" />));
2678
2757
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2679
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2680
Scheduler.unstable_advanceTime(2999);
2681
await advanceTimers(2999);
2682
// Since the timeout is infinite (or effectively infinite),
@@ -2763,12 +2685,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2685
2686
// Later we load the data.
2687
await resolveText('B');
2766
- expect(Scheduler).toFlushAndYield(['B']);
2688
+ await waitForAll(['B']);
2689
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2690
2691
// Start a long (infinite) transition.
2692
React.startTransition(() => ReactNoop.render(<App page="C" />));
2771
- expect(Scheduler).toFlushAndYield(['Suspend! [C]', 'Loading...']);
2693
+ await waitForAll(['Suspend! [C]', 'Loading...']);
2694
2695
// Even after lots of time has passed, we have still not yet flushed the
2696
// loading state.
@@ -2794,13 +2716,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2716
}
2717
2718
ReactNoop.render(<App />);
2797
- expect(Scheduler).toFlushAndYield([]);
2719
+ await waitForAll([]);
2720
2721
// Initial render.
2722
await act(async () => {
2723
React.startTransition(() => transitionToPage('A'));
2724
2803
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2725
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2726
// Only a short time is needed to unsuspend the initial loading state.
2727
Scheduler.unstable_advanceTime(400);
2728
await advanceTimers(400);
@@ -2809,14 +2731,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2731
2732
// Later we load the data.
2733
await resolveText('A');
2812
- expect(Scheduler).toFlushAndYield(['A']);
2734
+ await waitForAll(['A']);
2735
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2736
2737
// Start transition.
2738
await act(async () => {
2739
React.startTransition(() => transitionToPage('B'));
2740
2819
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2741
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2742
2743
Scheduler.unstable_advanceTime(2999);
2744
await advanceTimers(2999);
@@ -2827,14 +2749,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2749
2750
// Later we load the data.
2751
await resolveText('B');
2830
- expect(Scheduler).toFlushAndYield(['B']);
2752
+ await waitForAll(['B']);
2753
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2754
2755
// Start a long (infinite) transition.
2756
await act(async () => {
2757
React.startTransition(() => transitionToPage('C'));
2758
2837
- expect(Scheduler).toFlushAndYield(['Suspend! [C]', 'Loading...']);
2759
+ await waitForAll(['Suspend! [C]', 'Loading...']);
2760
2761
// Even after lots of time has passed, we have still not yet flushed the
2762
// loading state.
@@ -2864,13 +2786,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2786
}
2787
2788
ReactNoop.render(<App />);
2867
- expect(Scheduler).toFlushAndYield([]);
2789
+ await waitForAll([]);
2790
2791
// Initial render.
2792
await act(async () => {
2793
React.startTransition(() => transitionToPage('A'));
2794
2873
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
2795
+ await waitForAll(['Suspend! [A]', 'Loading...']);
2796
// Only a short time is needed to unsuspend the initial loading state.
2797
Scheduler.unstable_advanceTime(400);
2798
await advanceTimers(400);
@@ -2879,14 +2801,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2801
2802
// Later we load the data.
2803
await resolveText('A');
2882
- expect(Scheduler).toFlushAndYield(['A']);
2804
+ await waitForAll(['A']);
2805
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
2806
2807
// Start transition.
2808
await act(async () => {
2809
React.startTransition(() => transitionToPage('B'));
2810
2889
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
2811
+ await waitForAll(['Suspend! [B]', 'Loading...']);
2812
Scheduler.unstable_advanceTime(2999);
2813
await advanceTimers(2999);
2814
// Since the timeout is infinite (or effectively infinite),
@@ -2896,14 +2818,14 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2818
2819
// Later we load the data.
2820
await resolveText('B');
2899
- expect(Scheduler).toFlushAndYield(['B']);
2821
+ await waitForAll(['B']);
2822
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
2823
2824
// Start a long (infinite) transition.
2825
await act(async () => {
2826
React.startTransition(() => transitionToPage('C'));
2827
2906
- expect(Scheduler).toFlushAndYield(['Suspend! [C]', 'Loading...']);
2828
+ await waitForAll(['Suspend! [C]', 'Loading...']);
2829
2830
// Even after lots of time has passed, we have still not yet flushed the
2831
// loading state.
@@ -2931,9 +2853,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2853
2854
// Initial render.
2855
ReactNoop.render(<App page="A" />);
2934
- expect(Scheduler).toFlushAndYield(['Hi!', 'Suspend! [A]', 'Loading...']);
2856
+ await waitForAll(['Hi!', 'Suspend! [A]', 'Loading...']);
2857
await resolveText('A');
2936
- expect(Scheduler).toFlushAndYield(['Hi!', 'A']);
2858
+ await waitForAll(['Hi!', 'A']);
2859
expect(ReactNoop).toMatchRenderedOutput(
2860
<>
2861
<span prop="Hi!" />
@@ -2944,7 +2866,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2866
// Start transition.
2867
React.startTransition(() => ReactNoop.render(<App page="B" />));
2868
2947
- expect(Scheduler).toFlushAndYield(['Hi!', 'Suspend! [B]', 'Loading B...']);
2869
+ await waitForAll(['Hi!', 'Suspend! [B]', 'Loading B...']);
2870
2871
// Suspended
2872
expect(ReactNoop).toMatchRenderedOutput(
@@ -2955,7 +2877,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2877
);
2878
Scheduler.unstable_advanceTime(1800);
2879
await advanceTimers(1800);
2958
- expect(Scheduler).toFlushAndYield([]);
2880
+ await waitForAll([]);
2881
// We should still be suspended here because this loading state should be avoided.
2882
expect(ReactNoop).toMatchRenderedOutput(
2883
<>
@@ -2964,7 +2886,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2886
</>,
2887
);
2888
await resolveText('B');
2967
- expect(Scheduler).toFlushAndYield(['Hi!', 'B']);
2889
+ await waitForAll(['Hi!', 'B']);
2890
expect(ReactNoop).toMatchRenderedOutput(
2891
<>
2892
<span prop="Hi!" />
@@ -2994,7 +2916,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2916
2917
// Initial render.
2918
ReactNoop.render(<App page="A" />);
2997
- expect(Scheduler).toFlushAndYield(['Hi!', 'A']);
2919
+ await waitForAll(['Hi!', 'A']);
2920
expect(ReactNoop).toMatchRenderedOutput(
2921
<>
2922
<span prop="Hi!" />
@@ -3005,7 +2927,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2927
// Start transition.
2928
React.startTransition(() => ReactNoop.render(<App page="B" />));
2929
3008
- expect(Scheduler).toFlushAndYield(['Hi!', 'Suspend! [B]', 'Loading B...']);
2930
+ await waitForAll(['Hi!', 'Suspend! [B]', 'Loading B...']);
2931
2932
// Suspended
2933
expect(ReactNoop).toMatchRenderedOutput(
@@ -3016,7 +2938,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2938
);
2939
Scheduler.unstable_advanceTime(1800);
2940
await advanceTimers(1800);
3019
- expect(Scheduler).toFlushAndYield([]);
2941
+ await waitForAll([]);
2942
// We should still be suspended here because this loading state should be avoided.
2943
expect(ReactNoop).toMatchRenderedOutput(
2944
<>
@@ -3025,7 +2947,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2947
</>,
2948
);
2949
await resolveText('B');
3028
- expect(Scheduler).toFlushAndYield(['Hi!', 'B']);
2950
+ await waitForAll(['Hi!', 'B']);
2951
expect(ReactNoop).toMatchRenderedOutput(
2952
<>
2953
<span prop="Hi!" />
@@ -3051,13 +2973,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2973
await act(async () => {
2974
root.render(<App text="Initial" />);
2975
});
3054
- expect(Scheduler).toHaveYielded(['Suspend! [Initial]']);
2976
+ assertLog(['Suspend! [Initial]']);
2977
2978
// Resolve initial render
2979
await act(async () => {
2980
await resolveText('Initial');
2981
});
3060
- expect(Scheduler).toHaveYielded(['Initial']);
2982
+ assertLog(['Initial']);
2983
expect(root).toMatchRenderedOutput(<span prop="Initial" />);
2984
2985
await act(async () => {
@@ -3066,7 +2988,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2988
React.startTransition(() => {
2989
root.render(<App text="First update" />);
2990
});
3069
- expect(Scheduler).toFlushAndYield(['Suspend! [First update]']);
2991
+ await waitForAll(['Suspend! [First update]']);
2992
2993
// Should not display a fallback
2994
expect(root).toMatchRenderedOutput(<span prop="Initial" />);
@@ -3075,7 +2997,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2997
React.startTransition(() => {
2998
root.render(<App text="Second update" />);
2999
});
3078
- expect(Scheduler).toFlushAndYield(['Suspend! [Second update]']);
3000
+ await waitForAll(['Suspend! [Second update]']);
3001
3002
// Should not display a fallback
3003
expect(root).toMatchRenderedOutput(<span prop="Initial" />);
@@ -3113,22 +3035,19 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3035
root.render(<App />);
3036
});
3037
3116
- expect(Scheduler).toHaveYielded(['Foo']);
3038
+ assertLog(['Foo']);
3039
3040
await act(async () => {
3041
foo.setState({suspend: true});
3042
3121
- // In the regression that this covers, we would neglect to reset the
3122
- // current debug phase after suspending (in the catch block), so React
3123
- // thinks we're still inside the render phase.
3124
- expect(Scheduler).toFlushAndYieldThrough(['Suspend!']);
3043
+ await waitFor(['Suspend!']);
3044
3045
// Then when this setState happens, React would incorrectly fire a warning
3046
// about updates that happen the render phase (only fired by classes).
3047
foo.setState({suspend: false});
3048
});
3049
3131
- expect(Scheduler).toHaveYielded([
3050
+ assertLog([
3051
// First setState
3052
'Foo',
3053
]);
@@ -3159,7 +3078,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3078
3079
// Initial render.
3080
ReactNoop.render(<App showContent={false} />);
3162
- expect(Scheduler).toFlushAndYieldThrough(['Commit']);
3081
+ await waitFor(['Commit']);
3082
expect(ReactNoop).toMatchRenderedOutput(<div hidden={true} />);
3083
3084
// Start transition.
@@ -3167,16 +3086,16 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3086
ReactNoop.render(<App showContent={true} />);
3087
});
3088
3170
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
3089
+ await waitForAll(['Suspend! [A]', 'Loading...']);
3090
await resolveText('A');
3172
- expect(Scheduler).toFlushAndYieldThrough(['A', 'Commit']);
3091
+ await waitFor(['A', 'Commit']);
3092
expect(ReactNoop).toMatchRenderedOutput(
3093
<>
3094
<div hidden={true} />
3095
<span prop="A" />
3096
</>,
3097
);
3179
- expect(Scheduler).toFlushAndYield(['Offscreen']);
3098
+ await waitForAll(['Offscreen']);
3099
expect(ReactNoop).toMatchRenderedOutput(
3100
<>
3101
<div hidden={true}>Offscreen</div>
@@ -3208,27 +3127,26 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3127
3128
// Initial render.
3129
ReactNoop.render(<App showContent={false} />);
3211
- expect(Scheduler).toFlushAndYieldThrough(['Commit']);
3130
+ await waitFor(['Commit']);
3131
expect(ReactNoop).toMatchRenderedOutput(<div hidden={true} />);
3132
3214
- // Partially render through the hidden content.
3215
- expect(Scheduler).toFlushAndYieldThrough(['Suspend! [A]']);
3133
+ await waitFor(['Suspend! [A]']);
3134
3135
// Start transition.
3136
React.startTransition(() => {
3137
ReactNoop.render(<App showContent={true} />);
3138
});
3139
3222
- expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
3140
+ await waitForAll(['Suspend! [A]', 'Loading...']);
3141
await resolveText('A');
3224
- expect(Scheduler).toFlushAndYieldThrough(['A', 'Commit']);
3142
+ await waitFor(['A', 'Commit']);
3143
expect(ReactNoop).toMatchRenderedOutput(
3144
<>
3145
<div hidden={true} />
3146
<span prop="A" />
3147
</>,
3148
);
3231
- expect(Scheduler).toFlushAndYield(['A', 'Offscreen']);
3149
+ await waitForAll(['A', 'Offscreen']);
3150
expect(ReactNoop).toMatchRenderedOutput(
3151
<>
3152
<div hidden={true}>
@@ -3269,7 +3187,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3187
await act(async () => {
3188
root.render(<Parent />);
3189
});
3272
- expect(Scheduler).toHaveYielded(['A']);
3190
+ assertLog(['A']);
3191
expect(root).toMatchRenderedOutput(<span prop="A" />);
3192
3193
await act(async () => {
@@ -3283,7 +3201,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3201
await resolveText('C');
3202
setText('C');
3203
});
3286
- expect(Scheduler).toHaveYielded([
3204
+ assertLog([
3205
// First we attempt the high pri update. It suspends.
3206
'Suspend! [B]',
3207
'Loading...',
@@ -3323,7 +3241,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3241
await act(async () => {
3242
root.render(<Parent />);
3243
});
3326
- expect(Scheduler).toHaveYielded(['A']);
3244
+ assertLog(['A']);
3245
expect(root).toMatchRenderedOutput(<span prop="A" />);
3246
3247
await act(async () => {
@@ -3337,7 +3255,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3255
setText('C');
3256
});
3257
3340
- expect(Scheduler).toFlushAndYield([
3258
+ await waitForAll([
3259
// First we attempt the high pri update. It suspends.
3260
'Suspend! [B]',
3261
'Loading...',
@@ -3352,8 +3270,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3270
</>,
3271
);
3272
3355
- // Now flush the remaining work. The Idle update successfully finishes.
3356
- expect(Scheduler).toFlushAndYield(['C']);
3273
+ await waitForAll(['C']);
3274
expect(root).toMatchRenderedOutput(<span prop="C" />);
3275
});
3276
},
@@ -3392,13 +3309,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3309
await act(async () => {
3310
root.render(<App />);
3311
});
3395
- expect(Scheduler).toHaveYielded(['A']);
3312
+ assertLog(['A']);
3313
expect(root).toMatchRenderedOutput(<span prop="A" />);
3314
3315
await act(async () => {
3316
// Schedule an update inside the Suspense boundary that suspends.
3317
setAppText('B');
3401
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
3318
+ await waitForAll(['Suspend! [B]', 'Loading...']);
3319
});
3320
3321
expect(root).toMatchRenderedOutput(
@@ -3418,7 +3335,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3335
});
3336
});
3337
3421
- expect(Scheduler).toHaveYielded([
3338
+ assertLog([
3339
// First try to render the high pri update. Still suspended.
3340
'Suspend! [C]',
3341
'Loading...',
@@ -3477,7 +3394,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3394
await act(async () => {
3395
root.render(<Parent />);
3396
});
3480
- expect(Scheduler).toHaveYielded(['A']);
3397
+ assertLog(['A']);
3398
// At this point, the setState return path follows current fiber.
3399
expect(root).toMatchRenderedOutput(<span prop="A" />);
3400
@@ -3486,7 +3403,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3403
await act(async () => {
3404
setText('B');
3405
});
3489
- expect(Scheduler).toHaveYielded(['B']);
3406
+ assertLog(['B']);
3407
// Now the setState return path follows the *alternate* fiber.
3408
expect(root).toMatchRenderedOutput(<span prop="B" />);
3409
@@ -3494,7 +3411,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3411
await act(async () => {
3412
setText('C');
3413
});
3497
- expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
3414
+ assertLog(['Suspend! [C]', 'Loading...']);
3415
3416
// Commit. This will insert a fragment fiber to wrap around the component
3417
// that triggered the update.
@@ -3516,9 +3433,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3433
await act(async () => {
3434
setText('D');
3435
});
3519
- // Even though the fragment fiber is not part of the return path, we should
3520
- // be able to finish rendering.
3521
- expect(Scheduler).toHaveYielded(['D']);
3436
+ assertLog(['D']);
3437
expect(root).toMatchRenderedOutput(<span prop="D" />);
3438
},
3439
);
@@ -3554,7 +3469,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3469
await act(async () => {
3470
root.render(<Parent />);
3471
});
3557
- expect(Scheduler).toHaveYielded(['A']);
3472
+ assertLog(['A']);
3473
// At this point, the setState return path follows current fiber.
3474
expect(root).toMatchRenderedOutput(<span prop="A" />);
3475
@@ -3563,7 +3478,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3478
await act(async () => {
3479
setText('B');
3480
});
3566
- expect(Scheduler).toHaveYielded(['B']);
3481
+ assertLog(['B']);
3482
// Now the setState return path follows the *alternate* fiber.
3483
expect(root).toMatchRenderedOutput(<span prop="B" />);
3484
@@ -3571,7 +3486,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3486
await act(async () => {
3487
setText('C');
3488
});
3574
- expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
3489
+ assertLog(['Suspend! [C]', 'Loading...']);
3490
3491
// Commit. This will insert a fragment fiber to wrap around the component
3492
// that triggered the update.
@@ -3598,9 +3513,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3513
setText('E');
3514
});
3515
});
3601
- // Even though the fragment fiber is not part of the return path, we should
3602
- // be able to finish rendering.
3603
- expect(Scheduler).toHaveYielded(['Suspend! [D]', 'E']);
3516
+ assertLog(['Suspend! [D]', 'E']);
3517
expect(root).toMatchRenderedOutput(<span prop="E" />);
3518
},
3519
);
@@ -3663,7 +3576,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3576
await act(async () => {
3577
root.render(<Parent step={0} />);
3578
});
3666
- expect(Scheduler).toHaveYielded([
3579
+ assertLog([
3580
'Outer text: A',
3581
'Outer step: 0',
3582
'Inner text: A',
@@ -3683,7 +3596,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3596
await act(async () => {
3597
setText('B');
3598
});
3686
- expect(Scheduler).toHaveYielded([
3599
+ assertLog([
3600
'Outer text: B',
3601
'Outer step: 0',
3602
'Suspend! [Inner text: B]',
@@ -3709,10 +3622,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3622
});
3623
});
3624
3712
- // Only the outer part can update. The inner part should still show a
3713
- // fallback because we haven't finished loading B yet. Otherwise, the
3714
- // inner text would be inconsistent with the outer text.
3715
- expect(Scheduler).toHaveYielded([
3625
+ assertLog([
3626
'Outer text: B',
3627
'Outer step: 1',
3628
'Suspend! [Inner text: B]',
@@ -3733,11 +3643,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3643
await act(async () => {
3644
await resolveText('Inner text: B');
3645
});
3736
- expect(Scheduler).toHaveYielded([
3737
- 'Inner text: B',
3738
- 'Inner step: 1',
3739
- 'Commit Child',
3740
- ]);
3646
+ assertLog(['Inner text: B', 'Inner step: 1', 'Commit Child']);
3647
expect(root).toMatchRenderedOutput(
3648
<>
3649
<span prop="Outer text: B" />
@@ -3802,7 +3708,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3708
await act(async () => {
3709
root.render(<Parent step={0} />);
3710
});
3805
- expect(Scheduler).toHaveYielded(['Outer: A0', 'Inner: A0', 'Commit Child']);
3711
+ assertLog(['Outer: A0', 'Inner: A0', 'Commit Child']);
3712
expect(root).toMatchRenderedOutput(
3713
<>
3714
<span prop="Outer: A0" />
@@ -3814,11 +3720,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3720
await act(async () => {
3721
setText('B');
3722
});
3817
- expect(Scheduler).toHaveYielded([
3818
- 'Outer: B0',
3819
- 'Suspend! [Inner: B0]',
3820
- 'Loading...',
3821
- ]);
3723
+ assertLog(['Outer: B0', 'Suspend! [Inner: B0]', 'Loading...']);
3724
// Commit the placeholder
3725
await advanceTimers(250);
3726
expect(root).toMatchRenderedOutput(
@@ -3837,7 +3739,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3739
});
3740
});
3741
3840
- expect(Scheduler).toHaveYielded(['Outer: B1', 'Inner: B1', 'Commit Child']);
3742
+ assertLog(['Outer: B1', 'Inner: B1', 'Commit Child']);
3743
expect(root).toMatchRenderedOutput(
3744
<>
3745
<span prop="Outer: B1" />
@@ -3895,20 +3797,15 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3797
await act(async () => {
3798
root.render(<Root />);
3799
});
3898
- expect(Scheduler).toHaveYielded(['']);
3800
+ assertLog(['']);
3801
expect(root).toMatchRenderedOutput(<span prop="" />);
3802
3803
// Update to "a". That will suspend.
3804
await act(async () => {
3805
setTextWithShortTransition('a');
3904
- expect(Scheduler).toFlushAndYield([
3905
- 'Pending...',
3906
- '',
3907
- 'Suspend! [a]',
3908
- 'Loading...',
3909
- ]);
3806
+ await waitForAll(['Pending...', '', 'Suspend! [a]', 'Loading...']);
3807
});
3911
- expect(Scheduler).toHaveYielded([]);
3808
+ assertLog([]);
3809
expect(root).toMatchRenderedOutput(
3810
<>
3811
<span prop="Pending..." />
@@ -3919,7 +3816,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3816
// Update to "b". That will suspend, too.
3817
await act(async () => {
3818
setTextWithLongTransition('b');
3922
- expect(Scheduler).toFlushAndYield([
3819
+ await waitForAll([
3820
// Neither is resolved yet.
3821
'Pending...',
3822
'',
@@ -3927,7 +3824,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3824
'Loading...',
3825
]);
3826
});
3930
- expect(Scheduler).toHaveYielded([]);
3827
+ assertLog([]);
3828
expect(root).toMatchRenderedOutput(
3829
<>
3830
<span prop="Pending..." />
@@ -3939,7 +3836,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3836
await act(async () => {
3837
await resolveText('a');
3838
3942
- expect(Scheduler).toFlushAndYield(['Suspend! [b]', 'Loading...']);
3839
+ await waitForAll(['Suspend! [b]', 'Loading...']);
3840
expect(root).toMatchRenderedOutput(
3841
<>
3842
<span prop="Pending..." />
@@ -3951,7 +3848,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3848
await act(async () => {
3849
await resolveText('b');
3850
});
3954
- expect(Scheduler).toHaveYielded(['b']);
3851
+ assertLog(['b']);
3852
// The bug was that the pending state got stuck forever.
3853
expect(root).toMatchRenderedOutput(<span prop="b" />);
3854
});
@@ -3977,7 +3874,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3874
</Suspense>,
3875
);
3876
});
3980
- expect(Scheduler).toHaveYielded(['A']);
3877
+ assertLog(['A']);
3878
expect(root).toMatchRenderedOutput(<span prop="A" />);
3879
3880
await act(async () => {
@@ -3985,22 +3882,19 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3882
ReactNoop.idleUpdates(() => {
3883
setText('B');
3884
});
3988
- // Suspend the first update. The second update doesn't run because it has
3989
- // Idle priority.
3990
- expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
3885
+ await waitForAll(['Suspend! [B]', 'Loading...']);
3886
3887
// Commit the fallback. Now we'll try working on Idle.
3888
jest.runAllTimers();
3889
3995
- // It also suspends.
3996
- expect(Scheduler).toFlushAndYield(['Suspend! [B]']);
3890
+ await waitForAll(['Suspend! [B]']);
3891
});
3892
3893
await act(async () => {
3894
setText('B');
3895
await resolveText('B');
3896
});
4003
- expect(Scheduler).toHaveYielded(['B']);
3897
+ assertLog(['B']);
3898
expect(root).toMatchRenderedOutput(<span prop="B" />);
3899
});
3900
@@ -4026,7 +3920,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3920
</>,
3921
);
3922
});
4029
- expect(Scheduler).toHaveYielded(['A', 'Suspend! [Async]', 'Loading...']);
3923
+ assertLog(['A', 'Suspend! [Async]', 'Loading...']);
3924
expect(root).toMatchRenderedOutput(
3925
<>
3926
<span prop="A" />
@@ -4040,8 +3934,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3934
// Before the retry happens, schedule a new update.
3935
setText('B');
3936
4043
- // The update should be allowed to finish before the retry is attempted.
4044
- expect(Scheduler).toFlushUntilNextPaint(['B']);
3937
+ await waitForPaint(['B']);
3938
expect(root).toMatchRenderedOutput(
3939
<>
3940
<span prop="B" />
@@ -4049,8 +3942,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3942
</>,
3943
);
3944
});
4052
- // Then do the retry.
4053
- expect(Scheduler).toHaveYielded(['Async']);
3945
+ assertLog(['Async']);
3946
expect(root).toMatchRenderedOutput(
3947
<>
3948
<span prop="B" />
@@ -4087,13 +3979,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3979
await act(async () => {
3980
root.render(<App show={false} />);
3981
});
4090
- expect(Scheduler).toHaveYielded(['Mount Child']);
3982
+ assertLog(['Mount Child']);
3983
expect(root).toMatchRenderedOutput(<span prop="Child" />);
3984
3985
await act(async () => {
3986
root.render(<App show={true} />);
3987
});
4096
- expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']);
3988
+ assertLog(['Suspend! [Async]', 'Loading...']);
3989
expect(root).toMatchRenderedOutput(
3990
<>
3991
<span hidden={true} prop="Child" />
@@ -4104,7 +3996,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3996
await act(async () => {
3997
root.render(null);
3998
});
4107
- expect(Scheduler).toHaveYielded(['Unmount Child']);
3999
+ assertLog(['Unmount Child']);
4000
});
4001
4002
// @gate enableLegacyCache
@@ -4135,13 +4027,13 @@ describe('ReactSuspenseWithNoopRenderer', () => {
4027
await act(async () => {
4028
root.render(<App show={false} />);
4029
});
4138
- expect(Scheduler).toHaveYielded(['Mount Child']);
4030
+ assertLog(['Mount Child']);
4031
expect(root).toMatchRenderedOutput(<span prop="Child" />);
4032
4033
await act(async () => {
4034
root.render(<App show={true} />);
4035
});
4144
- expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']);
4036
+ assertLog(['Suspend! [Async]', 'Loading...']);
4037
expect(root).toMatchRenderedOutput(
4038
<>
4039
<span hidden={true} prop="Child" />
@@ -4152,7 +4044,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
4044
await act(async () => {
4045
root.render(null);
4046
});
4155
- expect(Scheduler).toHaveYielded(['Unmount Child']);
4047
+ assertLog(['Unmount Child']);
4048
});
4049
4050
// @gate enableLegacyCache
@@ -4202,7 +4094,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
4094
await act(async () => {
4095
root.render(<App showMore={false} />);
4096
});
4205
- expect(Scheduler).toHaveYielded([]);
4097
+ assertLog([]);
4098
expect(root).toMatchRenderedOutput(<div />);
4099
4100
// Update. This will cause two separate trees to suspend. The first tree
@@ -4221,7 +4113,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
4113
await act(async () => {
4114
root.render(<App showMore={true} />);
4115
});
4224
- expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...', 'Hi']);
4116
+ assertLog(['Suspend! [Async]', 'Loading...', 'Hi']);
4117
expect(root).toMatchRenderedOutput(
4118
<div>
4119
<span prop="Loading..." />