@samitouri / QOS-React-2 / commits / 58605f7988

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(