Use concurrent root in RTR (#28498)
Based on - https://github.com/facebook/react/pull/28497 - https://github.com/facebook/react/pull/28419 Reusing the disableLegacyMode flag, we set ReactTestRenderer to always render with concurrent root where legacy APIs are no longer available. If disableLegacyMode is false, we continue to allow the unstable_isConcurrent option determine the root type. Also checking a global `IS_REACT_NATIVE_TEST_ENVIRONMENT` so we can maintain the existing behavior for RN until we remove legacy root support there.
Jack Pope committed
Mar 26, 2024 at 18:53 UTC
bb66aa3cef4e42aee790200d03cf7a82659da121
8 files changed
+536
-274
packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js
+26
-31
@@ -46,45 +46,40 @@ describe('ErrorBoundaryReconciliation', () => {
46
fail ? <InvalidType /> : <span prop="BrokenRender" />;
47
});
48
49
- [true, false].forEach(isConcurrent => {
50
- async function sharedTest(ErrorBoundary, fallbackTagName) {
51
- let renderer;
49
+ async function sharedTest(ErrorBoundary, fallbackTagName) {
50
+ let renderer;
51
52
+ await act(() => {
53
+ renderer = ReactTestRenderer.create(
54
+ <ErrorBoundary fallbackTagName={fallbackTagName}>
55
+ <BrokenRender fail={false} />
56
+ </ErrorBoundary>,
57
+ {unstable_isConcurrent: true},
58
+ );
59
+ });
60
+ expect(renderer).toMatchRenderedOutput(<span prop="BrokenRender" />);
61
+ await expect(async () => {
62
await act(() => {
54
- renderer = ReactTestRenderer.create(
63
+ renderer.update(
64
<ErrorBoundary fallbackTagName={fallbackTagName}>
56
- <BrokenRender fail={false} />
65
+ <BrokenRender fail={true} />
66
</ErrorBoundary>,
58
- {unstable_isConcurrent: isConcurrent},
67
);
68
});
61
- expect(renderer).toMatchRenderedOutput(<span prop="BrokenRender" />);
62
-
63
- await expect(async () => {
64
- await act(() => {
65
- renderer.update(
66
- <ErrorBoundary fallbackTagName={fallbackTagName}>
67
- <BrokenRender fail={true} />
68
- </ErrorBoundary>,
69
- );
70
- });
71
- }).toErrorDev(isConcurrent ? ['invalid', 'invalid'] : ['invalid']);
72
- const Fallback = fallbackTagName;
73
- expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />);
74
- }
69
+ }).toErrorDev(['invalid', 'invalid']);
70
+ const Fallback = fallbackTagName;
71
+ expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />);
72
+ }
73
76
- describe(isConcurrent ? 'concurrent' : 'sync', () => {
77
- it('componentDidCatch can recover by rendering an element of the same type', () =>
78
- sharedTest(DidCatchErrorBoundary, 'span'));
74
+ it('componentDidCatch can recover by rendering an element of the same type', () =>
75
+ sharedTest(DidCatchErrorBoundary, 'span'));
76
80
- it('componentDidCatch can recover by rendering an element of a different type', () =>
81
- sharedTest(DidCatchErrorBoundary, 'div'));
77
+ it('componentDidCatch can recover by rendering an element of a different type', () =>
78
+ sharedTest(DidCatchErrorBoundary, 'div'));
79
83
- it('getDerivedStateFromError can recover by rendering an element of the same type', () =>
84
- sharedTest(GetDerivedErrorBoundary, 'span'));
80
+ it('getDerivedStateFromError can recover by rendering an element of the same type', () =>
81
+ sharedTest(GetDerivedErrorBoundary, 'span'));
82
86
- it('getDerivedStateFromError can recover by rendering an element of a different type', () =>
87
- sharedTest(GetDerivedErrorBoundary, 'div'));
88
- });
89
- });
83
+ it('getDerivedStateFromError can recover by rendering an element of a different type', () =>
84
+ sharedTest(GetDerivedErrorBoundary, 'div'));
85
});
packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+2
@@ -1451,6 +1451,7 @@ describe('ReactLazy', () => {
1451
});
1452
1453
describe('legacy mode', () => {
1454
+ // @gate !disableLegacyMode
1455
it('mount and reorder lazy elements (legacy mode)', async () => {
1456
class Child extends React.Component {
1457
componentDidMount() {
@@ -1520,6 +1521,7 @@ describe('ReactLazy', () => {
1521
expect(root).toMatchRenderedOutput('ba');
1522
});
1523
1524
+ // @gate !disableLegacyMode
1525
it('mount and reorder lazy types (legacy mode)', async () => {
1526
class Child extends React.Component {
1527
componentDidMount() {
packages/react-test-renderer/src/ReactTestRenderer.js
+7
-3
@@ -55,6 +55,7 @@ import {ConcurrentRoot, LegacyRoot} from 'react-reconciler/src/ReactRootTags';
55
import {
56
allowConcurrentByDefault,
57
enableReactTestRendererWarning,
58
+ disableLegacyMode,
59
} from 'shared/ReactFeatureFlags';
60
61
const act = React.act;
@@ -485,7 +486,10 @@ function create(
486
}
487
488
let createNodeMock = defaultTestOptions.createNodeMock;
488
- let isConcurrent = false;
489
+ const isConcurrentOnly =
490
+ disableLegacyMode === true &&
491
+ global.IS_REACT_NATIVE_TEST_ENVIRONMENT !== true;
492
+ let isConcurrent = isConcurrentOnly;
493
let isStrictMode = false;
494
let concurrentUpdatesByDefault = null;
495
if (typeof options === 'object' && options !== null) {
@@ -493,8 +497,8 @@ function create(
497
// $FlowFixMe[incompatible-type] found when upgrading Flow
498
createNodeMock = options.createNodeMock;
499
}
496
- if (options.unstable_isConcurrent === true) {
497
- isConcurrent = true;
500
+ if (isConcurrentOnly === false) {
501
+ isConcurrent = options.unstable_isConcurrent;
502
}
503
if (options.unstable_strictMode === true) {
504
isStrictMode = true;
packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js
+347
-153
@@ -14,14 +14,19 @@ const ReactFeatureFlags = require('shared/ReactFeatureFlags');
14
const React = require('react');
15
const ReactTestRenderer = require('react-test-renderer');
16
const {format: prettyFormat} = require('pretty-format');
17
+const InternalTestUtils = require('internal-test-utils');
18
+const waitForAll = InternalTestUtils.waitForAll;
19
+const act = InternalTestUtils.act;
20
+const Reconciler = require('react-reconciler/src/ReactFiberReconciler');
21
+const {
22
+ ConcurrentRoot,
23
+ LegacyRoot,
24
+} = require('react-reconciler/src/ReactRootTags');
25
26
// Isolate noop renderer
27
jest.resetModules();
28
const ReactNoop = require('react-noop-renderer');
29
22
-const InternalTestUtils = require('internal-test-utils');
23
-const waitForAll = InternalTestUtils.waitForAll;
24
-
30
// Kind of hacky, but we nullify all the instances to test the tree structure
31
// with jasmine's deep equality function, and test the instances separate. We
32
// also delete children props because testing them is more annoying and not
@@ -75,14 +80,63 @@ describe('ReactTestRenderer', () => {
80
'Warning: react-test-renderer is deprecated. See https://react.dev/warnings/react-test-renderer',
81
{withoutStack: true},
82
);
78
- global.IS_REACT_NATIVE_TEST_ENVIRONMENT = false;
83
});
84
81
- it('renders a simple component', () => {
85
+ describe('root tags', () => {
86
+ let createContainerSpy;
87
+ beforeEach(() => {
88
+ global.IS_REACT_NATIVE_TEST_ENVIRONMENT = false;
89
+ createContainerSpy = jest.spyOn(Reconciler, 'createContainer');
90
+ });
91
+
92
+ function expectTag(tag) {
93
+ expect(createContainerSpy).toHaveBeenCalledWith(
94
+ expect.anything(),
95
+ tag,
96
+ null,
97
+ expect.anything(),
98
+ null,
99
+ expect.anything(),
100
+ expect.anything(),
101
+ null,
102
+ );
103
+ }
104
+
105
+ // @gate disableLegacyMode
106
+ it('should render using concurrent root if disableLegacyMode', () => {
107
+ ReactTestRenderer.create(<div />);
108
+ expectTag(ConcurrentRoot);
109
+ });
110
+
111
+ // @gate !disableLegacyMode
112
+ it('should default to legacy root if not disableLegacyMode', () => {
113
+ ReactTestRenderer.create(<div />);
114
+ expectTag(LegacyRoot);
115
+ });
116
+
117
+ it('should allow unstable_isConcurrent if not disableLegacyMode', async () => {
118
+ ReactTestRenderer.create(<div />, {
119
+ unstable_isConcurrent: true,
120
+ });
121
+ ReactTestRenderer.create(<div />);
122
+ expectTag(ConcurrentRoot);
123
+ });
124
+
125
+ it('should render legacy root when RN test environment', async () => {
126
+ global.IS_REACT_NATIVE_TEST_ENVIRONMENT = true;
127
+ ReactTestRenderer.create(<div />);
128
+ expectTag(LegacyRoot);
129
+ });
130
+ });
131
+
132
+ it('renders a simple component', async () => {
133
function Link() {
134
return <a role="link" />;
135
}
85
- const renderer = ReactTestRenderer.create(<Link />);
136
+ let renderer;
137
+ await act(() => {
138
+ renderer = ReactTestRenderer.create(<Link />);
139
+ });
140
expect(renderer.toJSON()).toEqual({
141
type: 'a',
142
props: {role: 'link'},
@@ -90,19 +144,25 @@ describe('ReactTestRenderer', () => {
144
});
145
});
146
93
- it('renders a top-level empty component', () => {
147
+ it('renders a top-level empty component', async () => {
148
function Empty() {
149
return null;
150
}
97
- const renderer = ReactTestRenderer.create(<Empty />);
151
+ let renderer;
152
+ await act(() => {
153
+ renderer = ReactTestRenderer.create(<Empty />);
154
+ });
155
expect(renderer.toJSON()).toEqual(null);
156
});
157
101
- it('exposes a type flag', () => {
158
+ it('exposes a type flag', async () => {
159
function Link() {
160
return <a role="link" />;
161
}
105
- const renderer = ReactTestRenderer.create(<Link />);
162
+ let renderer;
163
+ await act(() => {
164
+ renderer = ReactTestRenderer.create(<Link />);
165
+ });
166
const object = renderer.toJSON();
167
expect(object.$$typeof).toBe(Symbol.for('react.test.json'));
168
@@ -114,7 +174,7 @@ describe('ReactTestRenderer', () => {
174
}
175
});
176
117
- it('can render a composite component', () => {
177
+ it('can render a composite component', async () => {
178
class Component extends React.Component {
179
render() {
180
return (
@@ -129,7 +189,10 @@ describe('ReactTestRenderer', () => {
189
return <moo />;
190
};
191
132
- const renderer = ReactTestRenderer.create(<Component />);
192
+ let renderer;
193
+ await act(() => {
194
+ renderer = ReactTestRenderer.create(<Component />);
195
+ });
196
expect(renderer.toJSON()).toEqual({
197
type: 'div',
198
props: {className: 'purple'},
@@ -137,7 +200,7 @@ describe('ReactTestRenderer', () => {
200
});
201
});
202
140
- it('renders some basics with an update', () => {
203
+ it('renders some basics with an update', async () => {
204
let renders = 0;
205
206
class Component extends React.Component {
@@ -169,7 +232,10 @@ describe('ReactTestRenderer', () => {
232
return null;
233
};
234
172
- const renderer = ReactTestRenderer.create(<Component />);
235
+ let renderer;
236
+ await act(() => {
237
+ renderer = ReactTestRenderer.create(<Component />);
238
+ });
239
expect(renderer.toJSON()).toEqual({
240
type: 'div',
241
props: {className: 'purple'},
@@ -178,7 +244,7 @@ describe('ReactTestRenderer', () => {
244
expect(renders).toBe(6);
245
});
246
181
- it('exposes the instance', () => {
247
+ it('exposes the instance', async () => {
248
class Mouse extends React.Component {
249
constructor() {
250
super();
@@ -191,7 +257,10 @@ describe('ReactTestRenderer', () => {
257
return <div>{this.state.mouse}</div>;
258
}
259
}
194
- const renderer = ReactTestRenderer.create(<Mouse />);
260
+ let renderer;
261
+ await act(() => {
262
+ renderer = ReactTestRenderer.create(<Mouse />);
263
+ });
264
265
expect(renderer.toJSON()).toEqual({
266
type: 'div',
@@ -200,7 +269,9 @@ describe('ReactTestRenderer', () => {
269
});
270
271
const mouse = renderer.getInstance();
203
- mouse.handleMoose();
272
+ await act(() => {
273
+ mouse.handleMoose();
274
+ });
275
expect(renderer.toJSON()).toEqual({
276
type: 'div',
277
children: ['moose'],
@@ -208,15 +279,20 @@ describe('ReactTestRenderer', () => {
279
});
280
});
281
211
- it('updates types', () => {
212
- const renderer = ReactTestRenderer.create(<div>mouse</div>);
282
+ it('updates types', async () => {
283
+ let renderer;
284
+ await act(() => {
285
+ renderer = ReactTestRenderer.create(<div>mouse</div>);
286
+ });
287
+
288
expect(renderer.toJSON()).toEqual({
289
type: 'div',
290
props: {},
291
children: ['mouse'],
292
});
218
-
219
- renderer.update(<span>mice</span>);
293
+ await act(() => {
294
+ renderer.update(<span>mice</span>);
295
+ });
296
expect(renderer.toJSON()).toEqual({
297
type: 'span',
298
props: {},
@@ -224,14 +300,18 @@ describe('ReactTestRenderer', () => {
300
});
301
});
302
227
- it('updates children', () => {
228
- const renderer = ReactTestRenderer.create(
229
- <div>
230
- <span key="a">A</span>
231
- <span key="b">B</span>
232
- <span key="c">C</span>
233
- </div>,
234
- );
303
+ it('updates children', async () => {
304
+ let renderer;
305
+ await act(() => {
306
+ renderer = ReactTestRenderer.create(
307
+ <div>
308
+ <span key="a">A</span>
309
+ <span key="b">B</span>
310
+ <span key="c">C</span>
311
+ </div>,
312
+ );
313
+ });
314
+
315
expect(renderer.toJSON()).toEqual({
316
type: 'div',
317
props: {},
@@ -242,13 +322,15 @@ describe('ReactTestRenderer', () => {
322
],
323
});
324
245
- renderer.update(
246
- <div>
247
- <span key="d">D</span>
248
- <span key="c">C</span>
249
- <span key="b">B</span>
250
- </div>,
251
- );
325
+ await act(() => {
326
+ renderer.update(
327
+ <div>
328
+ <span key="d">D</span>
329
+ <span key="c">C</span>
330
+ <span key="b">B</span>
331
+ </div>,
332
+ );
333
+ });
334
expect(renderer.toJSON()).toEqual({
335
type: 'div',
336
props: {},
@@ -260,7 +342,7 @@ describe('ReactTestRenderer', () => {
342
});
343
});
344
263
- it('does the full lifecycle', () => {
345
+ it('does the full lifecycle', async () => {
346
const log = [];
347
class Log extends React.Component {
348
render() {
@@ -275,9 +357,16 @@ describe('ReactTestRenderer', () => {
357
}
358
}
359
278
- const renderer = ReactTestRenderer.create(<Log key="foo" name="Foo" />);
279
- renderer.update(<Log key="bar" name="Bar" />);
280
- renderer.unmount();
360
+ let renderer;
361
+ await act(() => {
362
+ renderer = ReactTestRenderer.create(<Log key="foo" name="Foo" />);
363
+ });
364
+ await act(() => {
365
+ renderer.update(<Log key="bar" name="Bar" />);
366
+ });
367
+ await act(() => {
368
+ renderer.unmount();
369
+ });
370
371
expect(log).toEqual([
372
'render Foo',
@@ -289,14 +378,16 @@ describe('ReactTestRenderer', () => {
378
]);
379
});
380
292
- it('gives a ref to native components', () => {
381
+ it('gives a ref to native components', async () => {
382
const log = [];
294
- ReactTestRenderer.create(<div ref={r => log.push(r)} />);
383
+ await act(() => {
384
+ ReactTestRenderer.create(<div ref={r => log.push(r)} />);
385
+ });
386
expect(log).toEqual([null]);
387
});
388
389
// @gate !enableRefAsProp || !__DEV__
299
- it('warns correctly for refs on SFCs', () => {
390
+ it('warns correctly for refs on SFCs', async () => {
391
function Bar() {
392
return <div>Hello, world</div>;
393
}
@@ -312,8 +403,14 @@ describe('ReactTestRenderer', () => {
403
return <div ref={this.bazRef} />;
404
}
405
}
315
- ReactTestRenderer.create(<Baz />);
316
- expect(() => ReactTestRenderer.create(<Foo />)).toErrorDev(
406
+ await act(() => {
407
+ ReactTestRenderer.create(<Baz />);
408
+ });
409
+ await expect(async () => {
410
+ await act(() => {
411
+ ReactTestRenderer.create(<Foo />);
412
+ });
413
+ }).toErrorDev(
414
'Warning: Function components cannot be given refs. Attempts ' +
415
'to access this ref will fail. ' +
416
'Did you mean to use React.forwardRef()?\n' +
@@ -322,7 +419,7 @@ describe('ReactTestRenderer', () => {
419
);
420
});
421
325
- it('allows an optional createNodeMock function', () => {
422
+ it('allows an optional createNodeMock function', async () => {
423
const mockDivInstance = {appendChild: () => {}};
424
const mockInputInstance = {focus: () => {}};
425
const mockListItemInstance = {click: () => {}};
@@ -351,27 +448,41 @@ describe('ReactTestRenderer', () => {
448
return {};
449
}
450
}
354
- ReactTestRenderer.create(<div ref={r => log.push(r)} />, {createNodeMock});
355
- ReactTestRenderer.create(<input ref={r => log.push(r)} />, {
356
- createNodeMock,
451
+ await act(() => {
452
+ ReactTestRenderer.create(<div ref={r => log.push(r)} />, {
453
+ createNodeMock,
454
+ });
455
+ });
456
+ await act(() => {
457
+ ReactTestRenderer.create(<input ref={r => log.push(r)} />, {
458
+ createNodeMock,
459
+ });
460
+ });
461
+ await act(() => {
462
+ ReactTestRenderer.create(
463
+ <div>
464
+ <span>
465
+ <ul>
466
+ <li ref={r => log.push(r)} />
467
+ </ul>
468
+ <ul>
469
+ <li ref={r => log.push(r)} />
470
+ <li ref={r => log.push(r)} />
471
+ </ul>
472
+ </span>
473
+ </div>,
474
+ {createNodeMock, foobar: true},
475
+ );
476
+ });
477
+ await act(() => {
478
+ ReactTestRenderer.create(<Foo />, {createNodeMock});
479
+ });
480
+ await act(() => {
481
+ ReactTestRenderer.create(<div ref={r => log.push(r)} />);
482
+ });
483
+ await act(() => {
484
+ ReactTestRenderer.create(<div ref={r => log.push(r)} />, {});
485
});
358
- ReactTestRenderer.create(
359
- <div>
360
- <span>
361
- <ul>
362
- <li ref={r => log.push(r)} />
363
- </ul>
364
- <ul>
365
- <li ref={r => log.push(r)} />
366
- <li ref={r => log.push(r)} />
367
- </ul>
368
- </span>
369
- </div>,
370
- {createNodeMock, foobar: true},
371
- );
372
- ReactTestRenderer.create(<Foo />, {createNodeMock});
373
- ReactTestRenderer.create(<div ref={r => log.push(r)} />);
374
- ReactTestRenderer.create(<div ref={r => log.push(r)} />, {});
486
expect(log).toEqual([
487
mockDivInstance,
488
mockInputInstance,
@@ -396,7 +507,7 @@ describe('ReactTestRenderer', () => {
507
expect(() => inst.unmount()).not.toThrow();
508
});
509
399
- it('supports unmounting inner instances', () => {
510
+ it('supports unmounting inner instances', async () => {
511
let count = 0;
512
class Foo extends React.Component {
513
componentWillUnmount() {
@@ -406,19 +517,24 @@ describe('ReactTestRenderer', () => {
517
return <div />;
518
}
519
}
409
- const inst = ReactTestRenderer.create(
410
- <div>
411
- <Foo />
412
- </div>,
413
- {
414
- createNodeMock: () => 'foo',
415
- },
416
- );
417
- expect(() => inst.unmount()).not.toThrow();
520
+ let inst;
521
+ await act(() => {
522
+ inst = ReactTestRenderer.create(
523
+ <div>
524
+ <Foo />
525
+ </div>,
526
+ {
527
+ createNodeMock: () => 'foo',
528
+ },
529
+ );
530
+ });
531
+ await act(() => {
532
+ inst.unmount();
533
+ });
534
expect(count).toEqual(1);
535
});
536
421
- it('supports updates when using refs', () => {
537
+ it('supports updates when using refs', async () => {
538
const log = [];
539
const createNodeMock = element => {
540
log.push(element.type);
@@ -433,14 +549,19 @@ describe('ReactTestRenderer', () => {
549
);
550
}
551
}
436
- const inst = ReactTestRenderer.create(<Foo useDiv={true} />, {
437
- createNodeMock,
552
+ let inst;
553
+ await act(() => {
554
+ inst = ReactTestRenderer.create(<Foo useDiv={true} />, {
555
+ createNodeMock,
556
+ });
557
+ });
558
+ await act(() => {
559
+ inst.update(<Foo useDiv={false} />);
560
});
439
- inst.update(<Foo useDiv={false} />);
561
expect(log).toEqual(['div', 'span']);
562
});
563
443
- it('supports error boundaries', () => {
564
+ it('supports error boundaries', async () => {
565
const log = [];
566
class Angry extends React.Component {
567
render() {
@@ -489,13 +610,20 @@ describe('ReactTestRenderer', () => {
610
}
611
}
612
492
- const renderer = ReactTestRenderer.create(<Boundary />);
613
+ let renderer;
614
+ await act(() => {
615
+ renderer = ReactTestRenderer.create(<Boundary />, {
616
+ unstable_isConcurrent: true,
617
+ });
618
+ });
619
expect(renderer.toJSON()).toEqual({
620
type: 'div',
621
props: {},
622
children: ['Happy Birthday!'],
623
});
624
expect(log).toEqual([
625
+ 'Boundary render',
626
+ 'Angry render',
627
'Boundary render',
628
'Angry render',
629
'Boundary componentDidMount',
@@ -504,42 +632,53 @@ describe('ReactTestRenderer', () => {
632
]);
633
});
634
507
- it('can update text nodes', () => {
635
+ it('can update text nodes', async () => {
636
class Component extends React.Component {
637
render() {
638
return <div>{this.props.children}</div>;
639
}
640
}
641
514
- const renderer = ReactTestRenderer.create(<Component>Hi</Component>);
642
+ let renderer;
643
+ await act(() => {
644
+ renderer = ReactTestRenderer.create(<Component>Hi</Component>);
645
+ });
646
expect(renderer.toJSON()).toEqual({
647
type: 'div',
648
children: ['Hi'],
649
props: {},
650
});
520
- renderer.update(<Component>{['Hi', 'Bye']}</Component>);
651
+ await act(() => {
652
+ renderer.update(<Component>{['Hi', 'Bye']}</Component>);
653
+ });
654
expect(renderer.toJSON()).toEqual({
655
type: 'div',
656
children: ['Hi', 'Bye'],
657
props: {},
658
});
526
- renderer.update(<Component>Bye</Component>);
659
+ await act(() => {
660
+ renderer.update(<Component>Bye</Component>);
661
+ });
662
expect(renderer.toJSON()).toEqual({
663
type: 'div',
664
children: ['Bye'],
665
props: {},
666
});
532
- renderer.update(<Component>{42}</Component>);
667
+ await act(() => {
668
+ renderer.update(<Component>{42}</Component>);
669
+ });
670
expect(renderer.toJSON()).toEqual({
671
type: 'div',
672
children: ['42'],
673
props: {},
674
});
538
- renderer.update(
539
- <Component>
540
- <div />
541
- </Component>,
542
- );
675
+ await act(() => {
676
+ renderer.update(
677
+ <Component>
678
+ <div />
679
+ </Component>,
680
+ );
681
+ });
682
expect(renderer.toJSON()).toEqual({
683
type: 'div',
684
children: [
@@ -553,10 +692,13 @@ describe('ReactTestRenderer', () => {
692
});
693
});
694
556
- it('toTree() renders simple components returning host components', () => {
695
+ it('toTree() renders simple components returning host components', async () => {
696
const Qoo = () => <span className="Qoo">Hello World!</span>;
697
559
- const renderer = ReactTestRenderer.create(<Qoo />);
698
+ let renderer;
699
+ await act(() => {
700
+ renderer = ReactTestRenderer.create(<Qoo />);
701
+ });
702
const tree = renderer.toTree();
703
704
cleanNodeOrArray(tree);
@@ -578,13 +720,16 @@ describe('ReactTestRenderer', () => {
720
);
721
});
722
581
- it('toTree() handles nested Fragments', () => {
723
+ it('toTree() handles nested Fragments', async () => {
724
const Foo = () => (
725
<>
726
<>foo</>
727
</>
728
);
587
- const renderer = ReactTestRenderer.create(<Foo />);
729
+ let renderer;
730
+ await act(() => {
731
+ renderer = ReactTestRenderer.create(<Foo />);
732
+ });
733
const tree = renderer.toTree();
734
735
cleanNodeOrArray(tree);
@@ -600,14 +745,17 @@ describe('ReactTestRenderer', () => {
745
);
746
});
747
603
- it('toTree() handles null rendering components', () => {
748
+ it('toTree() handles null rendering components', async () => {
749
class Foo extends React.Component {
750
render() {
751
return null;
752
}
753
}
754
610
- const renderer = ReactTestRenderer.create(<Foo />);
755
+ let renderer;
756
+ await act(() => {
757
+ renderer = ReactTestRenderer.create(<Foo />);
758
+ });
759
const tree = renderer.toTree();
760
761
expect(tree.instance).toBeInstanceOf(Foo);
@@ -623,15 +771,18 @@ describe('ReactTestRenderer', () => {
771
});
772
});
773
626
- it('toTree() handles simple components that return arrays', () => {
774
+ it('toTree() handles simple components that return arrays', async () => {
775
const Foo = ({children}) => children;
776
629
- const renderer = ReactTestRenderer.create(
630
- <Foo>
631
- <div>One</div>
632
- <div>Two</div>
633
- </Foo>,
634
- );
777
+ let renderer;
778
+ await act(() => {
779
+ renderer = ReactTestRenderer.create(
780
+ <Foo>
781
+ <div>One</div>
782
+ <div>Two</div>
783
+ </Foo>,
784
+ );
785
+ });
786
787
const tree = renderer.toTree();
788
@@ -663,25 +814,28 @@ describe('ReactTestRenderer', () => {
814
);
815
});
816
666
- it('toTree() handles complicated tree of arrays', () => {
817
+ it('toTree() handles complicated tree of arrays', async () => {
818
class Foo extends React.Component {
819
render() {
820
return this.props.children;
821
}
822
}
823
673
- const renderer = ReactTestRenderer.create(
674
- <div>
675
- <Foo>
676
- <div>One</div>
677
- <div>Two</div>
824
+ let renderer;
825
+ await act(() => {
826
+ renderer = ReactTestRenderer.create(
827
+ <div>
828
<Foo>
679
- <div>Three</div>
829
+ <div>One</div>
830
+ <div>Two</div>
831
+ <Foo>
832
+ <div>Three</div>
833
+ </Foo>
834
</Foo>
681
- </Foo>
682
- <div>Four</div>
683
- </div>,
684
- );
835
+ <div>Four</div>
836
+ </div>,
837
+ );
838
+ });
839
840
const tree = renderer.toTree();
841
@@ -741,19 +895,22 @@ describe('ReactTestRenderer', () => {
895
);
896
});
897
744
- it('toTree() handles complicated tree of fragments', () => {
745
- const renderer = ReactTestRenderer.create(
746
- <>
898
+ it('toTree() handles complicated tree of fragments', async () => {
899
+ let renderer;
900
+ await act(() => {
901
+ renderer = ReactTestRenderer.create(
902
<>
748
- <div>One</div>
749
- <div>Two</div>
903
<>
751
- <div>Three</div>
904
+ <div>One</div>
905
+ <div>Two</div>
906
+ <>
907
+ <div>Three</div>
908
+ </>
909
</>
753
- </>
754
- <div>Four</div>
755
- </>,
756
- );
910
+ <div>Four</div>
911
+ </>,
912
+ );
913
+ });
914
915
const tree = renderer.toTree();
916
@@ -793,18 +950,22 @@ describe('ReactTestRenderer', () => {
950
);
951
});
952
796
- it('root instance and createNodeMock ref return the same value', () => {
953
+ it('root instance and createNodeMock ref return the same value', async () => {
954
const createNodeMock = ref => ({node: ref});
955
let refInst = null;
799
- const renderer = ReactTestRenderer.create(
800
- <div ref={ref => (refInst = ref)} />,
801
- {createNodeMock},
802
- );
956
+ let renderer;
957
+ await act(() => {
958
+ renderer = ReactTestRenderer.create(
959
+ <div ref={ref => (refInst = ref)} />,
960
+ {createNodeMock},
961
+ );
962
+ });
963
+
964
const root = renderer.getInstance();
965
expect(root).toEqual(refInst);
966
});
967
807
- it('toTree() renders complicated trees of composites and hosts', () => {
968
+ it('toTree() renders complicated trees of composites and hosts', async () => {
969
// SFC returning host. no children props.
970
const Qoo = () => <span className="Qoo">Hello World!</span>;
971
@@ -835,7 +996,11 @@ describe('ReactTestRenderer', () => {
996
}
997
}
998
838
- const renderer = ReactTestRenderer.create(<Bam />);
999
+ let renderer;
1000
+ await act(() => {
1001
+ renderer = ReactTestRenderer.create(<Bam />);
1002
+ });
1003
+
1004
const tree = renderer.toTree();
1005
1006
// we test for the presence of instances before nulling them out
@@ -894,30 +1059,45 @@ describe('ReactTestRenderer', () => {
1059
);
1060
});
1061
897
- it('can update text nodes when rendered as root', () => {
898
- const renderer = ReactTestRenderer.create(['Hello', 'world']);
1062
+ it('can update text nodes when rendered as root', async () => {
1063
+ let renderer;
1064
+ await act(() => {
1065
+ renderer = ReactTestRenderer.create(['Hello', 'world']);
1066
+ });
1067
expect(renderer.toJSON()).toEqual(['Hello', 'world']);
900
- renderer.update(42);
1068
+ await act(() => {
1069
+ renderer.update(42);
1070
+ });
1071
expect(renderer.toJSON()).toEqual('42');
902
- renderer.update([42, 'world']);
1072
+ await act(() => {
1073
+ renderer.update([42, 'world']);
1074
+ });
1075
expect(renderer.toJSON()).toEqual(['42', 'world']);
1076
});
1077
906
- it('can render and update root fragments', () => {
1078
+ it('can render and update root fragments', async () => {
1079
const Component = props => props.children;
1080
909
- const renderer = ReactTestRenderer.create([
910
- <Component key="a">Hi</Component>,
911
- <Component key="b">Bye</Component>,
912
- ]);
1081
+ let renderer;
1082
+ await act(() => {
1083
+ renderer = ReactTestRenderer.create([
1084
+ <Component key="a">Hi</Component>,
1085
+ <Component key="b">Bye</Component>,
1086
+ ]);
1087
+ });
1088
+
1089
expect(renderer.toJSON()).toEqual(['Hi', 'Bye']);
914
- renderer.update(<div />);
1090
+ await act(() => {
1091
+ renderer.update(<div />);
1092
+ });
1093
expect(renderer.toJSON()).toEqual({
1094
type: 'div',
1095
children: null,
1096
props: {},
1097
});
920
- renderer.update([<div key="a">goodbye</div>, 'world']);
1098
+ await act(() => {
1099
+ renderer.update([<div key="a">goodbye</div>, 'world']);
1100
+ });
1101
expect(renderer.toJSON()).toEqual([
1102
{
1103
type: 'div',
@@ -928,7 +1108,7 @@ describe('ReactTestRenderer', () => {
1108
]);
1109
});
1110
931
- it('supports context providers and consumers', () => {
1111
+ it('supports context providers and consumers', async () => {
1112
const {Consumer, Provider} = React.createContext('a');
1113
1114
function Child(props) {
@@ -943,7 +1123,10 @@ describe('ReactTestRenderer', () => {
1123
);
1124
}
1125
946
- const renderer = ReactTestRenderer.create(<App />);
1126
+ let renderer;
1127
+ await act(() => {
1128
+ renderer = ReactTestRenderer.create(<App />);
1129
+ });
1130
const child = renderer.root.findByType(Child);
1131
expect(child.children).toEqual(['b']);
1132
expect(prettyFormat(renderer.toTree())).toEqual(
@@ -965,7 +1148,7 @@ describe('ReactTestRenderer', () => {
1148
);
1149
});
1150
968
- it('supports modes', () => {
1151
+ it('supports modes', async () => {
1152
function Child(props) {
1153
return props.value;
1154
}
@@ -978,7 +1161,10 @@ describe('ReactTestRenderer', () => {
1161
);
1162
}
1163
981
- const renderer = ReactTestRenderer.create(<App value="a" />);
1164
+ let renderer;
1165
+ await act(() => {
1166
+ renderer = ReactTestRenderer.create(<App value="a" />);
1167
+ });
1168
const child = renderer.root.findByType(Child);
1169
expect(child.children).toEqual(['a']);
1170
expect(prettyFormat(renderer.toTree())).toEqual(
@@ -1002,7 +1188,7 @@ describe('ReactTestRenderer', () => {
1188
);
1189
});
1190
1005
- it('supports forwardRef', () => {
1191
+ it('supports forwardRef', async () => {
1192
const InnerRefed = React.forwardRef((props, ref) => (
1193
<div>
1194
<span ref={ref} />
@@ -1020,7 +1206,10 @@ describe('ReactTestRenderer', () => {
1206
}
1207
}
1208
1023
- const renderer = ReactTestRenderer.create(<App />);
1209
+ let renderer;
1210
+ await act(() => {
1211
+ renderer = ReactTestRenderer.create(<App />);
1212
+ });
1213
const tree = renderer.toTree();
1214
cleanNodeOrArray(tree);
1215
@@ -1065,12 +1254,17 @@ describe('ReactTestRenderer', () => {
1254
);
1255
ReactNoop.render(<App />);
1256
await waitForAll([]);
1068
- ReactTestRenderer.create(<App />);
1257
+ await act(() => {
1258
+ ReactTestRenderer.create(<App />);
1259
+ });
1260
});
1261
1071
- it('calling findByType() with an invalid component will fall back to "Unknown" for component name', () => {
1262
+ it('calling findByType() with an invalid component will fall back to "Unknown" for component name', async () => {
1263
const App = () => null;
1073
- const renderer = ReactTestRenderer.create(<App />);
1264
+ let renderer;
1265
+ await act(() => {
1266
+ renderer = ReactTestRenderer.create(<App />);
1267
+ });
1268
const NonComponent = {};
1269
1270
expect(() => {
packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.js
+42
-32
@@ -13,7 +13,7 @@ let ReactDOM;
13
let React;
14
let ReactCache;
15
let ReactTestRenderer;
16
-let waitForAll;
16
+let act;
17
18
describe('ReactTestRenderer', () => {
19
beforeEach(() => {
@@ -26,32 +26,28 @@ describe('ReactTestRenderer', () => {
26
ReactCache = require('react-cache');
27
ReactTestRenderer = require('react-test-renderer');
28
const InternalTestUtils = require('internal-test-utils');
29
- waitForAll = InternalTestUtils.waitForAll;
29
+ act = InternalTestUtils.act;
30
});
31
32
- it('should warn if used to render a ReactDOM portal', () => {
32
+ it('should warn if used to render a ReactDOM portal', async () => {
33
const container = document.createElement('div');
34
- expect(() => {
35
- let error;
36
- try {
34
+ let error;
35
+
36
+ await expect(async () => {
37
+ await act(() => {
38
ReactTestRenderer.create(ReactDOM.createPortal('foo', container));
38
- } catch (e) {
39
- error = e;
40
- }
41
- // After the update throws, a subsequent render is scheduled to
42
- // unmount the whole tree. This update also causes an error, so React
43
- // throws an AggregateError.
44
- const errors = error.errors;
45
- expect(errors.length).toBe(2);
46
- expect(errors[0].message.includes('indexOf is not a function')).toBe(
47
- true,
48
- );
49
- expect(errors[1].message.includes('indexOf is not a function')).toBe(
50
- true,
51
- );
39
+ }).catch(e => (error = e));
40
}).toErrorDev('An invalid container has been provided.', {
41
withoutStack: true,
42
});
43
+
44
+ // After the update throws, a subsequent render is scheduled to
45
+ // unmount the whole tree. This update also causes an error, so React
46
+ // throws an AggregateError.
47
+ const errors = error.errors;
48
+ expect(errors.length).toBe(2);
49
+ expect(errors[0].message.includes('indexOf is not a function')).toBe(true);
50
+ expect(errors[1].message.includes('indexOf is not a function')).toBe(true);
51
});
52
53
describe('timed out Suspense hidden subtrees should not be observable via toJSON', () => {
@@ -84,16 +80,23 @@ describe('ReactTestRenderer', () => {
80
);
81
};
82
87
- const root = ReactTestRenderer.create(<App text="initial" />);
88
- PendingResources.initial('initial');
89
- await waitForAll([]);
83
+ let root;
84
+ await act(() => {
85
+ root = ReactTestRenderer.create(<App text="initial" />);
86
+ });
87
+ await act(() => {
88
+ PendingResources.initial('initial');
89
+ });
90
expect(root.toJSON()).toEqual('initial');
91
92
- root.update(<App text="dynamic" />);
92
+ await act(() => {
93
+ root.update(<App text="dynamic" />);
94
+ });
95
expect(root.toJSON()).toEqual('fallback');
96
95
- PendingResources.dynamic('dynamic');
96
- await waitForAll([]);
97
+ await act(() => {
98
+ PendingResources.dynamic('dynamic');
99
+ });
100
expect(root.toJSON()).toEqual('dynamic');
101
});
102
@@ -108,16 +111,23 @@ describe('ReactTestRenderer', () => {
111
);
112
};
113
111
- const root = ReactTestRenderer.create(<App text="initial" />);
112
- PendingResources.initial('initial');
113
- await waitForAll([]);
114
+ let root;
115
+ await act(() => {
116
+ root = ReactTestRenderer.create(<App text="initial" />);
117
+ });
118
+ await act(() => {
119
+ PendingResources.initial('initial');
120
+ });
121
expect(root.toJSON().children).toEqual(['initial']);
122
116
- root.update(<App text="dynamic" />);
123
+ await act(() => {
124
+ root.update(<App text="dynamic" />);
125
+ });
126
expect(root.toJSON().children).toEqual(['fallback']);
127
119
- PendingResources.dynamic('dynamic');
120
- await waitForAll([]);
128
+ await act(() => {
129
+ PendingResources.dynamic('dynamic');
130
+ });
131
expect(root.toJSON().children).toEqual(['dynamic']);
132
});
133
});
packages/react-test-renderer/src/__tests__/ReactTestRendererAct-test.js
+5
-1
@@ -16,6 +16,7 @@ describe('ReactTestRenderer.act()', () => {
16
17
const InternalTestUtils = require('internal-test-utils');
18
assertLog = InternalTestUtils.assertLog;
19
+ global.IS_REACT_ACT_ENVIRONMENT = true;
20
});
21
22
// @gate __DEV__
@@ -91,7 +92,10 @@ describe('ReactTestRenderer.act()', () => {
92
});
93
return step;
94
}
94
- const root = ReactTestRenderer.create(null);
95
+ let root;
96
+ await act(() => {
97
+ root = ReactTestRenderer.create(null);
98
+ });
99
await act(async () => {
100
root.update(<App />);
101
});
packages/react-test-renderer/src/__tests__/ReactTestRendererTraversal-test.js
+64
-31
@@ -13,6 +13,7 @@
13
const React = require('react');
14
let ReactTestRenderer;
15
let Context;
16
+let act;
17
18
const RCTView = 'RCTView';
19
const View = props => <RCTView {...props} />;
@@ -21,6 +22,7 @@ describe('ReactTestRendererTraversal', () => {
22
beforeEach(() => {
23
jest.resetModules();
24
ReactTestRenderer = require('react-test-renderer');
25
+ act = require('internal-test-utils').act;
26
Context = React.createContext(null);
27
});
28
@@ -68,8 +70,11 @@ describe('ReactTestRendererTraversal', () => {
70
<View {...props} ref={ref} />
71
));
72
71
- it('initializes', () => {
72
- const render = ReactTestRenderer.create(<Example />);
73
+ it('initializes', async () => {
74
+ let render;
75
+ await act(() => {
76
+ render = ReactTestRenderer.create(<Example />);
77
+ });
78
const hasFooProp = node => node.props.hasOwnProperty('foo');
79
80
// assert .props, .type and .parent attributes
@@ -80,8 +85,12 @@ describe('ReactTestRendererTraversal', () => {
85
expect(foo.children[0].parent).toBe(foo);
86
});
87
83
- it('searches via .find() / .findAll()', () => {
84
- const render = ReactTestRenderer.create(<Example />);
88
+ it('searches via .find() / .findAll()', async () => {
89
+ let render;
90
+ await act(() => {
91
+ render = ReactTestRenderer.create(<Example />);
92
+ });
93
+
94
const hasFooProp = node => node.props.hasOwnProperty('foo');
95
const hasBarProp = node => node.props.hasOwnProperty('bar');
96
const hasBazProp = node => node.props.hasOwnProperty('baz');
@@ -135,8 +144,11 @@ describe('ReactTestRendererTraversal', () => {
144
expect(itself.findAll(hasBazProp)).toHaveLength(2);
145
});
146
138
- it('searches via .findByType() / .findAllByType()', () => {
139
- const render = ReactTestRenderer.create(<Example />);
147
+ it('searches via .findByType() / .findAllByType()', async () => {
148
+ let render;
149
+ await act(() => {
150
+ render = ReactTestRenderer.create(<Example />);
151
+ });
152
153
expect(() => render.root.findByType(ExampleFn)).not.toThrow(); // 1 match
154
expect(() => render.root.findByType(View)).not.toThrow(); // 1 match
@@ -159,8 +171,11 @@ describe('ReactTestRendererTraversal', () => {
171
expect(fn[0].findAllByType(View)).toHaveLength(1);
172
});
173
162
- it('searches via .findByProps() / .findAllByProps()', () => {
163
- const render = ReactTestRenderer.create(<Example />);
174
+ it('searches via .findByProps() / .findAllByProps()', async () => {
175
+ let render;
176
+ await act(() => {
177
+ render = ReactTestRenderer.create(<Example />);
178
+ });
179
const foo = 'foo';
180
const bar = 'bar';
181
const baz = 'baz';
@@ -182,8 +197,11 @@ describe('ReactTestRendererTraversal', () => {
197
expect(render.root.findAllByProps({qux})).toHaveLength(3);
198
});
199
185
- it('skips special nodes', () => {
186
- const render = ReactTestRenderer.create(<Example />);
200
+ it('skips special nodes', async () => {
201
+ let render;
202
+ await act(() => {
203
+ render = ReactTestRenderer.create(<Example />);
204
+ });
205
expect(render.root.findAllByType(React.Fragment)).toHaveLength(0);
206
expect(render.root.findAllByType(Context.Consumer)).toHaveLength(0);
207
expect(render.root.findAllByType(Context.Provider)).toHaveLength(0);
@@ -200,47 +218,62 @@ describe('ReactTestRendererTraversal', () => {
218
expect(nestedViews[2].parent).toBe(expectedParent);
219
});
220
203
- it('can have special nodes as roots', () => {
221
+ it('can have special nodes as roots', async () => {
222
const FR = React.forwardRef((props, ref) => <section {...props} />);
205
- expect(
206
- ReactTestRenderer.create(
223
+
224
+ let render1;
225
+ await act(() => {
226
+ render1 = ReactTestRenderer.create(
227
<FR>
228
<div />
229
<div />
230
</FR>,
211
- ).root.findAllByType('div').length,
212
- ).toBe(2);
213
- expect(
214
- ReactTestRenderer.create(
231
+ );
232
+ });
233
+ expect(render1.root.findAllByType('div').length).toBe(2);
234
+
235
+ let render2;
236
+ await act(() => {
237
+ render2 = ReactTestRenderer.create(
238
<>
239
<div />
240
<div />
241
</>,
219
- ).root.findAllByType('div').length,
220
- ).toBe(2);
221
- expect(
222
- ReactTestRenderer.create(
242
+ );
243
+ });
244
+ expect(render2.root.findAllByType('div').length).toBe(2);
245
+
246
+ let render3;
247
+ await act(() => {
248
+ render3 = ReactTestRenderer.create(
249
<React.Fragment key="foo">
250
<div />
251
<div />
252
</React.Fragment>,
227
- ).root.findAllByType('div').length,
228
- ).toBe(2);
229
- expect(
230
- ReactTestRenderer.create(
253
+ );
254
+ });
255
+ expect(render3.root.findAllByType('div').length).toBe(2);
256
+
257
+ let render4;
258
+ await act(() => {
259
+ render4 = ReactTestRenderer.create(
260
<React.StrictMode>
261
<div />
262
<div />
263
</React.StrictMode>,
235
- ).root.findAllByType('div').length,
236
- ).toBe(2);
237
- expect(
238
- ReactTestRenderer.create(
264
+ );
265
+ });
266
+ expect(render4.root.findAllByType('div').length).toBe(2);
267
+
268
+ let render5;
269
+ await act(() => {
270
+ render5 = ReactTestRenderer.create(
271
<Context.Provider value={null}>
272
<div />
273
<div />
274
</Context.Provider>,
243
- ).root.findAllByType('div').length,
244
- ).toBe(2);
275
+ );
276
+ });
277
+ expect(render5.root.findAllByType('div').length).toBe(2);
278
});
279
});
packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js
+43
-23
@@ -19,6 +19,7 @@ describe('ReactProfiler DevTools integration', () => {
19
let hook;
20
let waitForAll;
21
let waitFor;
22
+ let act;
23
24
beforeEach(() => {
25
global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
@@ -39,6 +40,7 @@ describe('ReactProfiler DevTools integration', () => {
40
const InternalTestUtils = require('internal-test-utils');
41
waitForAll = InternalTestUtils.waitForAll;
42
waitFor = InternalTestUtils.waitFor;
43
+ act = InternalTestUtils.act;
44
45
AdvanceTime = class extends React.Component {
46
static defaultProps = {
@@ -56,7 +58,7 @@ describe('ReactProfiler DevTools integration', () => {
58
};
59
});
60
59
- it('should auto-Profile all fibers if the DevTools hook is detected', () => {
61
+ it('should auto-Profile all fibers if the DevTools hook is detected', async () => {
62
const App = ({multiplier}) => {
63
Scheduler.unstable_advanceTime(2);
64
return (
@@ -71,7 +73,12 @@ describe('ReactProfiler DevTools integration', () => {
73
};
74
75
const onRender = jest.fn(() => {});
74
- const rendered = ReactTestRenderer.create(<App multiplier={1} />);
76
+ let rendered;
77
+ await act(() => {
78
+ rendered = ReactTestRenderer.create(<App multiplier={1} />, {
79
+ unstable_isConcurrent: true,
80
+ });
81
+ });
82
83
expect(hook.onCommitFiberRoot).toHaveBeenCalledTimes(1);
84
@@ -90,7 +97,9 @@ describe('ReactProfiler DevTools integration', () => {
97
12,
98
);
99
93
- rendered.update(<App multiplier={2} />);
100
+ await act(() => {
101
+ rendered.update(<App multiplier={2} />);
102
+ });
103
104
// Measure observable timing using the Profiler component.
105
// The time spent in App (above the Profiler) won't be included in the durations,
@@ -107,14 +116,18 @@ describe('ReactProfiler DevTools integration', () => {
116
);
117
});
118
110
- it('should reset the fiber stack correctly after an error when profiling host roots', () => {
119
+ it('should reset the fiber stack correctly after an error when profiling host roots', async () => {
120
Scheduler.unstable_advanceTime(20);
121
113
- const rendered = ReactTestRenderer.create(
114
- <div>
115
- <AdvanceTime byAmount={2} />
116
- </div>,
117
- );
122
+ let rendered;
123
+ await act(() => {
124
+ rendered = ReactTestRenderer.create(
125
+ <div>
126
+ <AdvanceTime byAmount={2} />
127
+ </div>,
128
+ {unstable_isConcurrent: true},
129
+ );
130
+ });
131
132
Scheduler.unstable_advanceTime(20);
133
@@ -122,22 +135,26 @@ describe('ReactProfiler DevTools integration', () => {
135
throw new Error('Oops!');
136
}
137
125
- expect(() => {
126
- rendered.update(
127
- <Throws>
128
- <AdvanceTime byAmount={3} />
129
- </Throws>,
130
- );
131
- }).toThrow('Oops!');
138
+ await expect(async () => {
139
+ await act(() => {
140
+ rendered.update(
141
+ <Throws>
142
+ <AdvanceTime byAmount={3} />
143
+ </Throws>,
144
+ );
145
+ });
146
+ }).rejects.toThrow('Oops!');
147
148
Scheduler.unstable_advanceTime(20);
149
135
- // But this should render correctly, if the profiler's fiber stack has been reset.
136
- rendered.update(
137
- <div>
138
- <AdvanceTime byAmount={7} />
139
- </div>,
140
- );
150
+ await act(() => {
151
+ // But this should render correctly, if the profiler's fiber stack has been reset.
152
+ rendered.update(
153
+ <div>
154
+ <AdvanceTime byAmount={7} />
155
+ </div>,
156
+ );
157
+ });
158
159
// Measure unobservable timing required by the DevTools profiler.
160
// At this point, the base time should include only the most recent (not failed) render.
@@ -154,7 +171,10 @@ describe('ReactProfiler DevTools integration', () => {
171
return text;
172
}
173
157
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
174
+ let root;
175
+ await act(() => {
176
+ root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
177
+ });
178
179
// Commit something
180
root.update(<Text text="A" />);