Codemod act -> await act (2/?) (#26335)
Similar to the rationale for `waitFor` (see #26285), we should always await the result of an `act` call so that microtasks have a chance to fire. This only affects the internal `act` that we use in our repo, for now. In the public `act` API, we don't yet require this; however, we effectively will for any update that triggers suspense once `use` lands. So we likely will start warning in an upcoming minor.
Andrew Clark committed
Mar 7, 2023 at 12:07 UTC
58605f798803081069971d9a0342ba08563248af
11 files changed
+168
-168
packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
+1
-1
@@ -161,7 +161,7 @@ describe('ReactDOMServerSuspense', () => {
161
expect(divB.tagName).toBe('DIV');
162
expect(divB.textContent).toBe('B');
163
164
- act(() => {
164
+ await act(async () => {
165
ReactDOMClient.hydrateRoot(parent, example);
166
});
167
packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js
+2
-10
@@ -153,7 +153,7 @@ describe('ReactDOMSuspensePlaceholder', () => {
153
);
154
}
155
156
- act(() => {
156
+ await act(async () => {
157
ReactDOM.render(<App />, container);
158
});
159
expect(container.innerHTML).toEqual(
@@ -161,15 +161,7 @@ describe('ReactDOMSuspensePlaceholder', () => {
161
'"display: none;"></span>Loading...',
162
);
163
164
- act(() => setIsVisible(true));
165
- expect(container.innerHTML).toEqual(
166
- '<span style="display: none;">Sibling</span><span style=' +
167
- '"display: none;"></span>Loading...',
168
- );
169
-
170
- await advanceTimers(500);
171
-
172
- Scheduler.unstable_flushAll();
164
+ await act(async () => setIsVisible(true));
165
166
expect(container.innerHTML).toEqual(
167
'<span style="display: inline;">Sibling</span><span style="">Async</span>',
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+60
-60
@@ -44,13 +44,13 @@ describe('ReactFabric', () => {
44
act = require('jest-react').act;
45
});
46
47
- it('should be able to create and render a native component', () => {
47
+ it('should be able to create and render a native component', async () => {
48
const View = createReactNativeComponentClass('RCTView', () => ({
49
validAttributes: {foo: true},
50
uiViewClassName: 'RCTView',
51
}));
52
53
- act(() => {
53
+ await act(async () => {
54
ReactFabric.render(<View foo="test" />, 1);
55
});
56
expect(nativeFabricUIManager.createNode).toBeCalled();
@@ -58,7 +58,7 @@ describe('ReactFabric', () => {
58
expect(nativeFabricUIManager.completeRoot).toBeCalled();
59
});
60
61
- it('should be able to create and update a native component', () => {
61
+ it('should be able to create and update a native component', async () => {
62
const View = createReactNativeComponentClass('RCTView', () => ({
63
validAttributes: {foo: true},
64
uiViewClassName: 'RCTView',
@@ -68,13 +68,13 @@ describe('ReactFabric', () => {
68
69
nativeFabricUIManager.createNode.mockReturnValue(firstNode);
70
71
- act(() => {
71
+ await act(async () => {
72
ReactFabric.render(<View foo="foo" />, 11);
73
});
74
75
expect(nativeFabricUIManager.createNode).toHaveBeenCalledTimes(1);
76
77
- act(() => {
77
+ await act(async () => {
78
ReactFabric.render(<View foo="bar" />, 11);
79
});
80
@@ -92,13 +92,13 @@ describe('ReactFabric', () => {
92
});
93
});
94
95
- it('should not call FabricUIManager.cloneNode after render for properties that have not changed', () => {
95
+ it('should not call FabricUIManager.cloneNode after render for properties that have not changed', async () => {
96
const Text = createReactNativeComponentClass('RCTText', () => ({
97
validAttributes: {foo: true},
98
uiViewClassName: 'RCTText',
99
}));
100
101
- act(() => {
101
+ await act(async () => {
102
ReactFabric.render(<Text foo="a">1</Text>, 11);
103
});
104
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -109,7 +109,7 @@ describe('ReactFabric', () => {
109
).not.toBeCalled();
110
111
// If no properties have changed, we shouldn't call cloneNode.
112
- act(() => {
112
+ await act(async () => {
113
ReactFabric.render(<Text foo="a">1</Text>, 11);
114
});
115
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -120,7 +120,7 @@ describe('ReactFabric', () => {
120
).not.toBeCalled();
121
122
// Only call cloneNode for the changed property (and not for text).
123
- act(() => {
123
+ await act(async () => {
124
ReactFabric.render(<Text foo="b">1</Text>, 11);
125
});
126
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -133,7 +133,7 @@ describe('ReactFabric', () => {
133
).not.toBeCalled();
134
135
// Only call cloneNode for the changed text (and no other properties).
136
- act(() => {
136
+ await act(async () => {
137
ReactFabric.render(<Text foo="b">2</Text>, 11);
138
});
139
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -148,7 +148,7 @@ describe('ReactFabric', () => {
148
).not.toBeCalled();
149
150
// Call cloneNode for both changed text and properties.
151
- act(() => {
151
+ await act(async () => {
152
ReactFabric.render(<Text foo="c">3</Text>, 11);
153
});
154
expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -163,13 +163,13 @@ describe('ReactFabric', () => {
163
).toHaveBeenCalledTimes(1);
164
});
165
166
- it('should only pass props diffs to FabricUIManager.cloneNode', () => {
166
+ it('should only pass props diffs to FabricUIManager.cloneNode', async () => {
167
const Text = createReactNativeComponentClass('RCTText', () => ({
168
validAttributes: {foo: true, bar: true},
169
uiViewClassName: 'RCTText',
170
}));
171
172
- act(() => {
172
+ await act(async () => {
173
ReactFabric.render(
174
<Text foo="a" bar="a">
175
1
@@ -184,7 +184,7 @@ describe('ReactFabric', () => {
184
nativeFabricUIManager.cloneNodeWithNewChildrenAndProps,
185
).not.toBeCalled();
186
187
- act(() => {
187
+ await act(async () => {
188
ReactFabric.render(
189
<Text foo="a" bar="b">
190
1
@@ -201,7 +201,7 @@ describe('ReactFabric', () => {
201
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
202
).toMatchSnapshot();
203
204
- act(() => {
204
+ await act(async () => {
205
ReactFabric.render(
206
<Text foo="b" bar="b">
207
2
@@ -219,7 +219,7 @@ describe('ReactFabric', () => {
219
).toMatchSnapshot();
220
});
221
222
- it('should call dispatchCommand for native refs', () => {
222
+ it('should call dispatchCommand for native refs', async () => {
223
const View = createReactNativeComponentClass('RCTView', () => ({
224
validAttributes: {foo: true},
225
uiViewClassName: 'RCTView',
@@ -228,7 +228,7 @@ describe('ReactFabric', () => {
228
nativeFabricUIManager.dispatchCommand.mockClear();
229
230
let viewRef;
231
- act(() => {
231
+ await act(async () => {
232
ReactFabric.render(
233
<View
234
ref={ref => {
@@ -249,7 +249,7 @@ describe('ReactFabric', () => {
249
);
250
});
251
252
- it('should warn and no-op if calling dispatchCommand on non native refs', () => {
252
+ it('should warn and no-op if calling dispatchCommand on non native refs', async () => {
253
class BasicClass extends React.Component {
254
render() {
255
return <React.Fragment />;
@@ -259,7 +259,7 @@ describe('ReactFabric', () => {
259
nativeFabricUIManager.dispatchCommand.mockReset();
260
261
let viewRef;
262
- act(() => {
262
+ await act(async () => {
263
ReactFabric.render(
264
<BasicClass
265
ref={ref => {
@@ -280,7 +280,7 @@ describe('ReactFabric', () => {
280
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
281
});
282
283
- it('should call sendAccessibilityEvent for native refs', () => {
283
+ it('should call sendAccessibilityEvent for native refs', async () => {
284
const View = createReactNativeComponentClass('RCTView', () => ({
285
validAttributes: {foo: true},
286
uiViewClassName: 'RCTView',
@@ -289,7 +289,7 @@ describe('ReactFabric', () => {
289
nativeFabricUIManager.sendAccessibilityEvent.mockClear();
290
291
let viewRef;
292
- act(() => {
292
+ await act(async () => {
293
ReactFabric.render(
294
<View
295
ref={ref => {
@@ -311,7 +311,7 @@ describe('ReactFabric', () => {
311
);
312
});
313
314
- it('should warn and no-op if calling sendAccessibilityEvent on non native refs', () => {
314
+ it('should warn and no-op if calling sendAccessibilityEvent on non native refs', async () => {
315
class BasicClass extends React.Component {
316
render() {
317
return <React.Fragment />;
@@ -321,7 +321,7 @@ describe('ReactFabric', () => {
321
nativeFabricUIManager.sendAccessibilityEvent.mockReset();
322
323
let viewRef;
324
- act(() => {
324
+ await act(async () => {
325
ReactFabric.render(
326
<BasicClass
327
ref={ref => {
@@ -363,7 +363,7 @@ describe('ReactFabric', () => {
363
expect(a).toBe(c);
364
});
365
366
- it('renders and reorders children', () => {
366
+ it('renders and reorders children', async () => {
367
const View = createReactNativeComponentClass('RCTView', () => ({
368
validAttributes: {title: true},
369
uiViewClassName: 'RCTView',
@@ -386,14 +386,14 @@ describe('ReactFabric', () => {
386
const before = 'abcdefghijklmnopqrst';
387
const after = 'mxhpgwfralkeoivcstzy';
388
389
- act(() => {
389
+ await act(async () => {
390
ReactFabric.render(<Component chars={before} />, 11);
391
});
392
expect(
393
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
394
).toMatchSnapshot();
395
396
- act(() => {
396
+ await act(async () => {
397
ReactFabric.render(<Component chars={after} />, 11);
398
});
399
expect(
@@ -401,7 +401,7 @@ describe('ReactFabric', () => {
401
).toMatchSnapshot();
402
});
403
404
- it('recreates host parents even if only children changed', () => {
404
+ it('recreates host parents even if only children changed', async () => {
405
const View = createReactNativeComponentClass('RCTView', () => ({
406
validAttributes: {title: true},
407
uiViewClassName: 'RCTView',
@@ -428,7 +428,7 @@ describe('ReactFabric', () => {
428
429
const ref = React.createRef();
430
// Wrap in a host node.
431
- act(() => {
431
+ await act(async () => {
432
ReactFabric.render(
433
<View>
434
<Component ref={ref} />
@@ -450,7 +450,7 @@ describe('ReactFabric', () => {
450
).toMatchSnapshot();
451
});
452
453
- it('calls setState with no arguments', () => {
453
+ it('calls setState with no arguments', async () => {
454
let mockArgs;
455
class Component extends React.Component {
456
componentDidMount() {
@@ -461,13 +461,13 @@ describe('ReactFabric', () => {
461
}
462
}
463
464
- act(() => {
464
+ await act(async () => {
465
ReactFabric.render(<Component />, 11);
466
});
467
expect(mockArgs.length).toEqual(0);
468
});
469
470
- it('should call complete after inserting children', () => {
470
+ it('should call complete after inserting children', async () => {
471
const View = createReactNativeComponentClass('RCTView', () => ({
472
validAttributes: {foo: true},
473
uiViewClassName: 'RCTView',
@@ -483,7 +483,7 @@ describe('ReactFabric', () => {
483
);
484
});
485
486
- act(() => {
486
+ await act(async () => {
487
ReactFabric.render(
488
<View foo="a">
489
<View foo="b" />
@@ -494,7 +494,7 @@ describe('ReactFabric', () => {
494
expect(snapshots).toMatchSnapshot();
495
});
496
497
- it('should not throw when <View> is used inside of a <Text> ancestor', () => {
497
+ it('should not throw when <View> is used inside of a <Text> ancestor', async () => {
498
const Image = createReactNativeComponentClass('RCTImage', () => ({
499
validAttributes: {},
500
uiViewClassName: 'RCTImage',
@@ -508,7 +508,7 @@ describe('ReactFabric', () => {
508
uiViewClassName: 'RCTView',
509
}));
510
511
- act(() => {
511
+ await act(async () => {
512
ReactFabric.render(
513
<Text>
514
<View />
@@ -517,7 +517,7 @@ describe('ReactFabric', () => {
517
);
518
});
519
520
- act(() => {
520
+ await act(async () => {
521
ReactFabric.render(
522
<Text>
523
<Image />
@@ -527,7 +527,7 @@ describe('ReactFabric', () => {
527
});
528
});
529
530
- it('should console error for text not inside of a <Text> ancestor', () => {
530
+ it('should console error for text not inside of a <Text> ancestor', async () => {
531
const ScrollView = createReactNativeComponentClass('RCTScrollView', () => ({
532
validAttributes: {},
533
uiViewClassName: 'RCTScrollView',
@@ -541,14 +541,14 @@ describe('ReactFabric', () => {
541
uiViewClassName: 'RCTView',
542
}));
543
544
- expect(() => {
545
- act(() => {
544
+ await expect(async () => {
545
+ await act(async () => {
546
ReactFabric.render(<View>this should warn</View>, 11);
547
});
548
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
549
550
- expect(() => {
551
- act(() => {
550
+ await expect(async () => {
551
+ await act(async () => {
552
ReactFabric.render(
553
<Text>
554
<ScrollView>hi hello hi</ScrollView>
@@ -559,7 +559,7 @@ describe('ReactFabric', () => {
559
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
560
});
561
562
- it('should not throw for text inside of an indirect <Text> ancestor', () => {
562
+ it('should not throw for text inside of an indirect <Text> ancestor', async () => {
563
const Text = createReactNativeComponentClass('RCTText', () => ({
564
validAttributes: {},
565
uiViewClassName: 'RCTText',
@@ -567,7 +567,7 @@ describe('ReactFabric', () => {
567
568
const Indirection = () => 'Hi';
569
570
- act(() => {
570
+ await act(async () => {
571
ReactFabric.render(
572
<Text>
573
<Indirection />
@@ -577,7 +577,7 @@ describe('ReactFabric', () => {
577
});
578
});
579
580
- it('dispatches events to the last committed props', () => {
580
+ it('dispatches events to the last committed props', async () => {
581
const View = createReactNativeComponentClass('RCTView', () => ({
582
validAttributes: {},
583
uiViewClassName: 'RCTView',
@@ -591,7 +591,7 @@ describe('ReactFabric', () => {
591
const touchStart = jest.fn();
592
const touchStart2 = jest.fn();
593
594
- act(() => {
594
+ await act(async () => {
595
ReactFabric.render(<View onTouchStart={touchStart} />, 11);
596
});
597
@@ -617,7 +617,7 @@ describe('ReactFabric', () => {
617
expect(touchStart).toBeCalled();
618
expect(touchStart2).not.toBeCalled();
619
620
- act(() => {
620
+ await act(async () => {
621
ReactFabric.render(<View onTouchStart={touchStart2} />, 11);
622
});
623
@@ -631,7 +631,7 @@ describe('ReactFabric', () => {
631
});
632
633
describe('skipBubbling', () => {
634
- it('should skip bubbling to ancestor if specified', () => {
634
+ it('should skip bubbling to ancestor if specified', async () => {
635
const View = createReactNativeComponentClass('RCTView', () => ({
636
validAttributes: {},
637
uiViewClassName: 'RCTView',
@@ -665,7 +665,7 @@ describe('ReactFabric', () => {
665
666
const event = {};
667
668
- act(() => {
668
+ await act(async () => {
669
ReactFabric.render(
670
<View
671
onSkippedBubblingEventCapture={ancestorCapture}
@@ -724,7 +724,7 @@ describe('ReactFabric', () => {
724
});
725
});
726
727
- it('dispatches event with target as instance', () => {
727
+ it('dispatches event with target as instance', async () => {
728
const View = createReactNativeComponentClass('RCTView', () => ({
729
validAttributes: {
730
id: true,
@@ -752,7 +752,7 @@ describe('ReactFabric', () => {
752
const ref1 = React.createRef();
753
const ref2 = React.createRef();
754
755
- act(() => {
755
+ await act(async () => {
756
ReactFabric.render(
757
<View id="parent">
758
<View
@@ -815,7 +815,7 @@ describe('ReactFabric', () => {
815
expect.assertions(6);
816
});
817
818
- it('findHostInstance_DEPRECATED should warn if used to find a host component inside StrictMode', () => {
818
+ it('findHostInstance_DEPRECATED should warn if used to find a host component inside StrictMode', async () => {
819
const View = createReactNativeComponentClass('RCTView', () => ({
820
validAttributes: {foo: true},
821
uiViewClassName: 'RCTView',
@@ -834,7 +834,7 @@ describe('ReactFabric', () => {
834
}
835
}
836
837
- act(() => {
837
+ await act(async () => {
838
ReactFabric.render(
839
<ContainsStrictModeChild ref={n => (parent = n)} />,
840
11,
@@ -856,7 +856,7 @@ describe('ReactFabric', () => {
856
expect(match).toBe(child);
857
});
858
859
- it('findHostInstance_DEPRECATED should warn if passed a component that is inside StrictMode', () => {
859
+ it('findHostInstance_DEPRECATED should warn if passed a component that is inside StrictMode', async () => {
860
const View = createReactNativeComponentClass('RCTView', () => ({
861
validAttributes: {foo: true},
862
uiViewClassName: 'RCTView',
@@ -871,7 +871,7 @@ describe('ReactFabric', () => {
871
}
872
}
873
874
- act(() => {
874
+ await act(async () => {
875
ReactFabric.render(
876
<StrictMode>
877
<IsInStrictMode ref={n => (parent = n)} />
@@ -895,7 +895,7 @@ describe('ReactFabric', () => {
895
expect(match).toBe(child);
896
});
897
898
- it('findNodeHandle should warn if used to find a host component inside StrictMode', () => {
898
+ it('findNodeHandle should warn if used to find a host component inside StrictMode', async () => {
899
const View = createReactNativeComponentClass('RCTView', () => ({
900
validAttributes: {foo: true},
901
uiViewClassName: 'RCTView',
@@ -914,7 +914,7 @@ describe('ReactFabric', () => {
914
}
915
}
916
917
- act(() => {
917
+ await act(async () => {
918
ReactFabric.render(
919
<ContainsStrictModeChild ref={n => (parent = n)} />,
920
11,
@@ -934,7 +934,7 @@ describe('ReactFabric', () => {
934
expect(match).toBe(child._nativeTag);
935
});
936
937
- it('findNodeHandle should warn if passed a component that is inside StrictMode', () => {
937
+ it('findNodeHandle should warn if passed a component that is inside StrictMode', async () => {
938
const View = createReactNativeComponentClass('RCTView', () => ({
939
validAttributes: {foo: true},
940
uiViewClassName: 'RCTView',
@@ -949,7 +949,7 @@ describe('ReactFabric', () => {
949
}
950
}
951
952
- act(() => {
952
+ await act(async () => {
953
ReactFabric.render(
954
<StrictMode>
955
<IsInStrictMode ref={n => (parent = n)} />
@@ -971,7 +971,7 @@ describe('ReactFabric', () => {
971
expect(match).toBe(child._nativeTag);
972
});
973
974
- it('should no-op if calling sendAccessibilityEvent on unmounted refs', () => {
974
+ it('should no-op if calling sendAccessibilityEvent on unmounted refs', async () => {
975
const View = createReactNativeComponentClass('RCTView', () => ({
976
validAttributes: {foo: true},
977
uiViewClassName: 'RCTView',
@@ -980,7 +980,7 @@ describe('ReactFabric', () => {
980
nativeFabricUIManager.sendAccessibilityEvent.mockReset();
981
982
let viewRef;
983
- act(() => {
983
+ await act(async () => {
984
ReactFabric.render(
985
<View
986
ref={ref => {
@@ -991,7 +991,7 @@ describe('ReactFabric', () => {
991
);
992
});
993
const dangerouslyRetainedViewRef = viewRef;
994
- act(() => {
994
+ await act(async () => {
995
ReactFabric.stopSurface(11);
996
});
997
packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js
+39
-33
@@ -30,7 +30,7 @@ beforeEach(() => {
30
* If the corresponding array of keys is null, the returned element at that
31
* index will also be null.
32
*/
33
-function mockRenderKeys(keyLists) {
33
+async function mockRenderKeys(keyLists) {
34
const ReactFabric = require('react-native-renderer/fabric');
35
const createReactNativeComponentClass =
36
require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
@@ -43,10 +43,12 @@ function mockRenderKeys(keyLists) {
43
uiViewClassName: 'RCTMockView',
44
}));
45
46
- return keyLists.map(keyList => {
46
+ const result = [];
47
+ for (let i = 0; i < keyLists.length; i++) {
48
+ const keyList = keyLists[i];
49
if (Array.isArray(keyList)) {
50
const refs = keyList.map(key => undefined);
49
- act(() => {
51
+ await act(async () => {
52
ReactFabric.render(
53
<MockView>
54
{keyList.map((key, index) => (
@@ -62,27 +64,31 @@ function mockRenderKeys(keyLists) {
64
);
65
});
66
// Clone `refs` to ignore future passes.
65
- return [...refs];
67
+ result.push([...refs]);
68
+ continue;
69
}
70
if (keyList == null) {
68
- act(() => {
71
+ await act(async () => {
72
ReactFabric.stopSurface(mockContainerTag);
73
});
71
- return null;
74
+ result.push(null);
75
+ continue;
76
}
77
throw new TypeError(
78
`Invalid 'keyLists' element of type ${typeof keyList}.`,
79
);
76
- });
80
+ }
81
+
82
+ return result;
83
}
84
85
describe('blur', () => {
80
- test('blur() invokes TextInputState', () => {
86
+ test('blur() invokes TextInputState', async () => {
87
const {
88
TextInputState,
89
} = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
90
85
- const [[fooRef]] = mockRenderKeys([['foo']]);
91
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
92
93
fooRef.blur();
94
@@ -91,12 +97,12 @@ describe('blur', () => {
97
});
98
99
describe('focus', () => {
94
- test('focus() invokes TextInputState', () => {
100
+ test('focus() invokes TextInputState', async () => {
101
const {
102
TextInputState,
103
} = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
104
99
- const [[fooRef]] = mockRenderKeys([['foo']]);
105
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
106
107
fooRef.focus();
108
@@ -105,8 +111,8 @@ describe('focus', () => {
111
});
112
113
describe('measure', () => {
108
- test('component.measure(...) invokes callback', () => {
109
- const [[fooRef]] = mockRenderKeys([['foo']]);
114
+ test('component.measure(...) invokes callback', async () => {
115
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
116
117
const callback = jest.fn();
118
fooRef.measure(callback);
@@ -115,8 +121,8 @@ describe('measure', () => {
121
expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 0, 0]]);
122
});
123
118
- test('unmounted.measure(...) does nothing', () => {
119
- const [[fooRef]] = mockRenderKeys([['foo'], null]);
124
+ test('unmounted.measure(...) does nothing', async () => {
125
+ const [[fooRef]] = await mockRenderKeys([['foo'], null]);
126
127
const callback = jest.fn();
128
fooRef.measure(callback);
@@ -127,8 +133,8 @@ describe('measure', () => {
133
});
134
135
describe('measureInWindow', () => {
130
- test('component.measureInWindow(...) invokes callback', () => {
131
- const [[fooRef]] = mockRenderKeys([['foo']]);
136
+ test('component.measureInWindow(...) invokes callback', async () => {
137
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
138
139
const callback = jest.fn();
140
fooRef.measureInWindow(callback);
@@ -137,8 +143,8 @@ describe('measureInWindow', () => {
143
expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
144
});
145
140
- test('unmounted.measureInWindow(...) does nothing', () => {
141
- const [[fooRef]] = mockRenderKeys([['foo'], null]);
146
+ test('unmounted.measureInWindow(...) does nothing', async () => {
147
+ const [[fooRef]] = await mockRenderKeys([['foo'], null]);
148
149
const callback = jest.fn();
150
fooRef.measureInWindow(callback);
@@ -149,8 +155,8 @@ describe('measureInWindow', () => {
155
});
156
157
describe('measureLayout', () => {
152
- test('component.measureLayout(component, ...) invokes callback', () => {
153
- const [[fooRef, barRef]] = mockRenderKeys([['foo', 'bar']]);
158
+ test('component.measureLayout(component, ...) invokes callback', async () => {
159
+ const [[fooRef, barRef]] = await mockRenderKeys([['foo', 'bar']]);
160
161
const successCallback = jest.fn();
162
const failureCallback = jest.fn();
@@ -160,8 +166,8 @@ describe('measureLayout', () => {
166
expect(successCallback.mock.calls).toEqual([[1, 1, 100, 100]]);
167
});
168
163
- test('unmounted.measureLayout(component, ...) does nothing', () => {
164
- const [[fooRef, barRef]] = mockRenderKeys([
169
+ test('unmounted.measureLayout(component, ...) does nothing', async () => {
170
+ const [[fooRef, barRef]] = await mockRenderKeys([
171
['foo', 'bar'],
172
['foo', null],
173
]);
@@ -174,8 +180,8 @@ describe('measureLayout', () => {
180
expect(successCallback).not.toHaveBeenCalled();
181
});
182
177
- test('component.measureLayout(unmounted, ...) does nothing', () => {
178
- const [[fooRef, barRef]] = mockRenderKeys([
183
+ test('component.measureLayout(unmounted, ...) does nothing', async () => {
184
+ const [[fooRef, barRef]] = await mockRenderKeys([
185
['foo', 'bar'],
186
[null, 'bar'],
187
]);
@@ -188,8 +194,8 @@ describe('measureLayout', () => {
194
expect(successCallback).not.toHaveBeenCalled();
195
});
196
191
- test('unmounted.measureLayout(unmounted, ...) does nothing', () => {
192
- const [[fooRef, barRef]] = mockRenderKeys([['foo', 'bar'], null]);
197
+ test('unmounted.measureLayout(unmounted, ...) does nothing', async () => {
198
+ const [[fooRef, barRef]] = await mockRenderKeys([['foo', 'bar'], null]);
199
200
const successCallback = jest.fn();
201
const failureCallback = jest.fn();
@@ -201,8 +207,8 @@ describe('measureLayout', () => {
207
});
208
209
describe('unstable_getBoundingClientRect', () => {
204
- test('component.unstable_getBoundingClientRect() returns DOMRect', () => {
205
- const [[fooRef]] = mockRenderKeys([['foo']]);
210
+ test('component.unstable_getBoundingClientRect() returns DOMRect', async () => {
211
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
212
213
const rect = fooRef.unstable_getBoundingClientRect();
214
@@ -217,8 +223,8 @@ describe('unstable_getBoundingClientRect', () => {
223
});
224
});
225
220
- test('unmounted.unstable_getBoundingClientRect() returns empty DOMRect', () => {
221
- const [[fooRef]] = mockRenderKeys([['foo'], null]);
226
+ test('unmounted.unstable_getBoundingClientRect() returns empty DOMRect', async () => {
227
+ const [[fooRef]] = await mockRenderKeys([['foo'], null]);
228
229
const rect = fooRef.unstable_getBoundingClientRect();
230
@@ -228,12 +234,12 @@ describe('unstable_getBoundingClientRect', () => {
234
});
235
236
describe('setNativeProps', () => {
231
- test('setNativeProps(...) invokes setNativeProps on Fabric UIManager', () => {
237
+ test('setNativeProps(...) invokes setNativeProps on Fabric UIManager', async () => {
238
const {
239
UIManager,
240
} = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
241
236
- const [[fooRef]] = mockRenderKeys([['foo']]);
242
+ const [[fooRef]] = await mockRenderKeys([['foo']]);
243
fooRef.setNativeProps({foo: 'baz'});
244
245
expect(UIManager.updateView).not.toBeCalled();
packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.js
+1
-1
@@ -102,7 +102,7 @@ describe('ReactIncrementalScheduling', () => {
102
return text;
103
}
104
105
- act(() => {
105
+ await act(async () => {
106
ReactNoop.renderToRootWithID(<Text text="a:1" />, 'a');
107
ReactNoop.renderToRootWithID(<Text text="b:1" />, 'b');
108
ReactNoop.renderToRootWithID(<Text text="c:1" />, 'c');
packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js
+1
-1
@@ -26,7 +26,7 @@ describe('internal act()', () => {
26
}
27
28
const calledLog = [];
29
- act(() => {
29
+ await act(async () => {
30
ReactNoop.render(
31
<App
32
callback={() => {
packages/react-reconciler/src/__tests__/ReactOffscreen-test.js
+2
-2
@@ -1992,7 +1992,7 @@ describe('ReactOffscreen', () => {
1992
}
1993
1994
const root = ReactNoop.createRoot();
1995
- await act(() => {
1995
+ await act(async () => {
1996
root.render(<App />);
1997
});
1998
@@ -2052,7 +2052,7 @@ describe('ReactOffscreen', () => {
2052
}
2053
2054
const root = ReactNoop.createRoot();
2055
- await act(() => {
2055
+ await act(async () => {
2056
root.render(<App />);
2057
});
2058
assertLog(['attach child']);
packages/react-reconciler/src/__tests__/ReactThenable-test.js
+1
-1
@@ -782,7 +782,7 @@ describe('ReactThenable', () => {
782
}
783
784
const root = ReactNoop.createRoot();
785
- await act(() => {
785
+ await act(async () => {
786
root.render(<Parent />);
787
});
788
assertLog(['childShouldSuspend: false, showChild: true', 'Child']);
packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js
+8
-8
@@ -2208,7 +2208,7 @@ describe('ReactInteractionTracing', () => {
2208
const root = ReactNoop.createRoot({
2209
unstable_transitionCallbacks: transitionCallbacks,
2210
});
2211
- await act(() => {
2211
+ await act(async () => {
2212
startTransition(() => root.render(<App />), {name: 'transition'});
2213
ReactNoop.expire(1000);
2214
advanceTimers(1000);
@@ -2221,7 +2221,7 @@ describe('ReactInteractionTracing', () => {
2221
'onTransitionStart(transition, 0)',
2222
]);
2223
2224
- await act(() => {
2224
+ await act(async () => {
2225
resolveText('Text');
2226
ReactNoop.expire(1000);
2227
advanceTimers(1000);
@@ -2232,7 +2232,7 @@ describe('ReactInteractionTracing', () => {
2232
'onTransitionComplete(transition, 0, 2000)',
2233
]);
2234
2235
- await act(() => {
2235
+ await act(async () => {
2236
resolveText('Hidden Text');
2237
ReactNoop.expire(1000);
2238
advanceTimers(1000);
@@ -2343,7 +2343,7 @@ describe('ReactInteractionTracing', () => {
2343
unstable_transitionCallbacks: transitionCallbacks,
2344
});
2345
2346
- await act(() => {
2346
+ await act(async () => {
2347
startTransition(() => root.render(<App />), {name: 'transition'});
2348
ReactNoop.expire(1000);
2349
advanceTimers(1000);
@@ -2361,7 +2361,7 @@ describe('ReactInteractionTracing', () => {
2361
'onTransitionProgress(transition, 0, 1000, [two])',
2362
]);
2363
2364
- await act(() => {
2364
+ await act(async () => {
2365
resolveText('Text Two');
2366
ReactNoop.expire(1000);
2367
advanceTimers(1000);
@@ -2416,7 +2416,7 @@ describe('ReactInteractionTracing', () => {
2416
unstable_transitionCallbacks: getTransitionCallbacks('root two'),
2417
});
2418
2419
- await act(() => {
2419
+ await act(async () => {
2420
startTransition(() => rootOne.render(<App name="one" />), {
2421
name: 'transition one',
2422
});
@@ -2438,7 +2438,7 @@ describe('ReactInteractionTracing', () => {
2438
'onTransitionProgress(transition two, 0, 1000, [two]) /root two/',
2439
]);
2440
2441
- await act(() => {
2441
+ await act(async () => {
2442
caches[0].resolve('Text one');
2443
ReactNoop.expire(1000);
2444
advanceTimers(1000);
@@ -2450,7 +2450,7 @@ describe('ReactInteractionTracing', () => {
2450
'onTransitionComplete(transition one, 0, 2000) /root one/',
2451
]);
2452
2453
- await act(() => {
2453
+ await act(async () => {
2454
resolveText('Text two');
2455
ReactNoop.expire(1000);
2456
advanceTimers(1000);
packages/use-sync-external-store/src/__tests__/useSyncExternalStoreNative-test.js
+4
-4
@@ -117,7 +117,7 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
117
}
118
119
const root = ReactNoop.createRoot();
120
- await act(() => {
120
+ await act(async () => {
121
root.render(<App />);
122
});
123
assertLog(['client']);
@@ -161,13 +161,13 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
161
}
162
163
const root = ReactNoop.createRoot();
164
- act(() => root.render(<App />));
164
+ await act(async () => root.render(<App />));
165
166
assertLog(['A0', 'B0']);
167
expect(root).toMatchRenderedOutput('A0B0');
168
169
// Update b but not a
170
- await act(() => {
170
+ await act(async () => {
171
store.set({a: 0, b: 1});
172
});
173
// Only b re-renders
@@ -175,7 +175,7 @@ describe('useSyncExternalStore (userspace shim, server rendering)', () => {
175
expect(root).toMatchRenderedOutput('A0B1');
176
177
// Update a but not b
178
- await act(() => {
178
+ await act(async () => {
179
store.set({a: 1, b: 1});
180
});
181
// Only a re-renders
packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
+49
-47
@@ -142,19 +142,19 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
142
143
const container = document.createElement('div');
144
const root = createRoot(container);
145
- await act(() => root.render(<App />));
145
+ await act(async () => root.render(<App />));
146
147
assertLog(['Initial']);
148
expect(container.textContent).toEqual('Initial');
149
150
- await act(() => {
150
+ await act(async () => {
151
store.set('Updated');
152
});
153
assertLog(['Updated']);
154
expect(container.textContent).toEqual('Updated');
155
});
156
157
- test('skips re-rendering if nothing changes', () => {
157
+ test('skips re-rendering if nothing changes', async () => {
158
const store = createExternalStore('Initial');
159
160
function App() {
@@ -164,13 +164,13 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
164
165
const container = document.createElement('div');
166
const root = createRoot(container);
167
- act(() => root.render(<App />));
167
+ await act(async () => root.render(<App />));
168
169
assertLog(['Initial']);
170
expect(container.textContent).toEqual('Initial');
171
172
// Update to the same value
173
- act(() => {
173
+ await act(async () => {
174
store.set('Initial');
175
});
176
// Should not re-render
@@ -192,19 +192,19 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
192
193
const container = document.createElement('div');
194
const root = createRoot(container);
195
- await act(() => root.render(<App />));
195
+ await act(async () => root.render(<App />));
196
197
assertLog([0]);
198
expect(container.textContent).toEqual('0');
199
200
- await act(() => {
200
+ await act(async () => {
201
storeA.set(1);
202
});
203
assertLog([1]);
204
expect(container.textContent).toEqual('1');
205
206
// Switch stores and update in the same batch
207
- act(() => {
207
+ await act(async () => {
208
ReactDOM.flushSync(() => {
209
// This update will be disregarded
210
storeA.set(2);
@@ -216,7 +216,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
216
expect(container.textContent).toEqual('0');
217
218
// Update A
219
- await act(() => {
219
+ await act(async () => {
220
storeA.set(3);
221
});
222
// Nothing happened, because we're no longer subscribed to A
@@ -224,7 +224,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
224
expect(container.textContent).toEqual('0');
225
226
// Update B
227
- await act(() => {
227
+ await act(async () => {
228
storeB.set(1);
229
});
230
assertLog([1]);
@@ -254,13 +254,13 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
254
255
const container = document.createElement('div');
256
const root = createRoot(container);
257
- act(() => root.render(<App />));
257
+ await act(async () => root.render(<App />));
258
259
assertLog(['A0', 'B0']);
260
expect(container.textContent).toEqual('A0B0');
261
262
// Update b but not a
263
- await act(() => {
263
+ await act(async () => {
264
store.set({a: 0, b: 1});
265
});
266
// Only b re-renders
@@ -268,7 +268,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
268
expect(container.textContent).toEqual('A0B1');
269
270
// Update a but not b
271
- await act(() => {
271
+ await act(async () => {
272
store.set({a: 1, b: 1});
273
});
274
// Only a re-renders
@@ -295,7 +295,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
295
296
const container = document.createElement('div');
297
const root = createRoot(container);
298
- act(() => root.render(<App />));
298
+ await act(async () => root.render(<App />));
299
assertLog([0, 'Passive effect: 0']);
300
301
// Schedule an update. We'll intentionally not use `act` so that we can
@@ -323,7 +323,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
323
},
324
);
325
326
- test('mutating the store in between render and commit when getSnapshot has changed', () => {
326
+ test('mutating the store in between render and commit when getSnapshot has changed', async () => {
327
const store = createExternalStore({a: 1, b: 1});
328
329
const getSnapshotA = () => store.getState().a;
@@ -365,11 +365,11 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
365
366
const container = document.createElement('div');
367
const root = createRoot(container);
368
- act(() => root.render(<App />));
368
+ await act(async () => root.render(<App />));
369
assertLog(['A1']);
370
expect(container.textContent).toEqual('A1');
371
372
- act(() => {
372
+ await act(async () => {
373
// Change getSnapshot and update the store in the same batch
374
setStep(1);
375
});
@@ -383,7 +383,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
383
expect(container.textContent).toEqual('B2');
384
});
385
386
- test('mutating the store in between render and commit when getSnapshot has _not_ changed', () => {
386
+ test('mutating the store in between render and commit when getSnapshot has _not_ changed', async () => {
387
// Same as previous test, but `getSnapshot` does not change
388
const store = createExternalStore({a: 1, b: 1});
389
@@ -423,13 +423,13 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
423
424
const container = document.createElement('div');
425
const root = createRoot(container);
426
- act(() => root.render(<App />));
426
+ await act(async () => root.render(<App />));
427
assertLog(['A1']);
428
expect(container.textContent).toEqual('A1');
429
430
// This will cause a layout effect, and in the layout effect we'll update
431
// the store
432
- act(() => {
432
+ await act(async () => {
433
setStep(1);
434
});
435
assertLog([
@@ -463,7 +463,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
463
464
const container = document.createElement('div');
465
const root = createRoot(container);
466
- act(() =>
466
+ await act(async () =>
467
root.render(
468
<>
469
<Child1 />
@@ -474,14 +474,14 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
474
assertLog([0, 0]);
475
expect(container.textContent).toEqual('00');
476
477
- await act(() => {
477
+ await act(async () => {
478
store.set(1);
479
});
480
assertLog([1, 1, 'Reset back to 0', 0, 0]);
481
expect(container.textContent).toEqual('00');
482
});
483
484
- test('uses the latest getSnapshot, even if it changed in the same batch as a store update', () => {
484
+ test('uses the latest getSnapshot, even if it changed in the same batch as a store update', async () => {
485
const store = createExternalStore({a: 0, b: 0});
486
487
const getSnapshotA = () => store.getState().a;
@@ -497,11 +497,11 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
497
498
const container = document.createElement('div');
499
const root = createRoot(container);
500
- act(() => root.render(<App />));
500
+ await act(async () => root.render(<App />));
501
assertLog([0]);
502
503
// Update the store and getSnapshot at the same time
504
- act(() => {
504
+ await act(async () => {
505
ReactDOM.flushSync(() => {
506
setGetSnapshot(() => getSnapshotB);
507
store.set({a: 1, b: 2});
@@ -546,7 +546,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
546
const errorBoundary = React.createRef(null);
547
const container = document.createElement('div');
548
const root = createRoot(container);
549
- act(() =>
549
+ await act(async () =>
550
root.render(
551
<ErrorBoundary ref={errorBoundary}>
552
<App />
@@ -557,7 +557,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
557
expect(container.textContent).toEqual('0');
558
559
// Update that throws in a getSnapshot. We can catch it with an error boundary.
560
- await act(() => {
560
+ await act(async () => {
561
store.set({value: 1, throwInGetSnapshot: true, throwInIsEqual: false});
562
});
563
if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
@@ -573,7 +573,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
573
expect(container.textContent).toEqual('Error in getSnapshot');
574
});
575
576
- test('Infinite loop if getSnapshot keeps returning new reference', () => {
576
+ test('Infinite loop if getSnapshot keeps returning new reference', async () => {
577
const store = createExternalStore({});
578
579
function App() {
@@ -584,8 +584,10 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
584
const container = document.createElement('div');
585
const root = createRoot(container);
586
587
- expect(() => {
588
- expect(() => act(() => root.render(<App />))).toThrow(
587
+ await expect(async () => {
588
+ expect(() =>
589
+ ReactDOM.flushSync(async () => root.render(<App />)),
590
+ ).toThrow(
591
'Maximum update depth exceeded. This can happen when a component repeatedly ' +
592
'calls setState inside componentWillUpdate or componentDidUpdate. React limits ' +
593
'the number of nested updates to prevent infinite loops.',
@@ -610,15 +612,15 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
612
613
// Initial render that reads a snapshot of NaN. This is OK because we use
614
// Object.is algorithm to compare values.
613
- await act(() => root.render(<App />));
615
+ await act(async () => root.render(<App />));
616
expect(container.textContent).toEqual('NaN');
617
618
// Update to real number
617
- await act(() => store.set(123));
619
+ await act(async () => store.set(123));
620
expect(container.textContent).toEqual('123');
621
622
// Update back to NaN
621
- await act(() => store.set('not a number'));
623
+ await act(async () => store.set('not a number'));
624
expect(container.textContent).toEqual('NaN');
625
});
626
@@ -646,13 +648,13 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
648
649
const container = document.createElement('div');
650
const root = createRoot(container);
649
- act(() => root.render(<App />));
651
+ await act(async () => root.render(<App />));
652
653
assertLog(['App', 'Selector', 'A0']);
654
expect(container.textContent).toEqual('A0');
655
656
// Update the store
655
- await act(() => {
657
+ await act(async () => {
658
store.set({a: 1, b: 0});
659
});
660
assertLog([
@@ -705,13 +707,13 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
707
708
const container = document.createElement('div');
709
const root = createRoot(container);
708
- act(() => root.render(<App />));
710
+ await act(async () => root.render(<App />));
711
712
assertLog(['A0', 'B0']);
713
expect(container.textContent).toEqual('A0B0');
714
715
// Update b but not a
714
- await act(() => {
716
+ await act(async () => {
717
store.set({a: 0, b: 1});
718
});
719
// Only b re-renders
@@ -719,7 +721,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
721
expect(container.textContent).toEqual('A0B1');
722
723
// Update a but not b
722
- await act(() => {
724
+ await act(async () => {
725
store.set({a: 1, b: 1});
726
});
727
// Only a re-renders
@@ -752,7 +754,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
754
const serverRenderedDiv = container.getElementsByTagName('div')[0];
755
756
if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
755
- act(() => {
757
+ await act(async () => {
758
ReactDOMClient.hydrateRoot(container, <App />);
759
});
760
assertLog([
@@ -768,7 +770,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
770
// currently hydrating, so `getServerSnapshot` is not called on the
771
// client. To avoid this server mismatch warning, user must account for
772
// this themselves and return the correct value inside `getSnapshot`.
771
- act(() => {
773
+ await act(async () => {
774
expect(() => ReactDOM.hydrate(<App />, container)).toErrorDev(
775
'Text content did not match',
776
);
@@ -795,12 +797,12 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
797
798
const container = document.createElement('div');
799
const root = createRoot(container);
798
- await act(() => root.render(<App />));
800
+ await act(async () => root.render(<App />));
801
802
assertLog(['INITIAL']);
803
expect(container.textContent).toEqual('INITIAL');
804
803
- await act(() => {
805
+ await act(async () => {
806
store.set('Updated');
807
});
808
assertLog(['UPDATED']);
@@ -858,12 +860,12 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
860
861
const container = document.createElement('div');
862
const root = createRoot(container);
861
- await act(() => {
863
+ await act(async () => {
864
root.render(<App step={0} />);
865
});
866
assertLog(['Inline selector', 'A', 'B', 'C', 'Sibling: 0']);
867
866
- await act(() => {
868
+ await act(async () => {
869
root.render(<App step={1} />);
870
});
871
assertLog([
@@ -918,7 +920,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
920
921
const container = document.createElement('div');
922
const root = createRoot(container);
921
- await act(() =>
923
+ await act(async () =>
924
root.render(
925
<ErrorBoundary>
926
<App />
@@ -963,7 +965,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
965
966
const container = document.createElement('div');
967
const root = createRoot(container);
966
- await act(() =>
968
+ await act(async () =>
969
root.render(
970
<ErrorBoundary>
971
<App />
@@ -974,7 +976,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
976
expect(container.textContent).toEqual('A');
977
978
await expect(async () => {
977
- await act(() => {
979
+ await act(async () => {
980
store.set({});
981
});
982
}).toWarnDev(