From 6fe44c23e321319d77c634eade68d60e59658477 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 7 Mar 2023 12:05:00 -0500 Subject: [PATCH] Codemod act -> await act (3/?) 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. --- .../src/__tests__/StrictEffectsMode-test.js | 70 +++++++++--------- ...StrictEffectsModeDefaults-test.internal.js | 74 +++++++++---------- .../src/__tests__/useEffectEvent-test.js | 60 ++++++++------- .../useMutableSource-test.internal.js | 8 +- .../useMutableSourceHydration-test.js | 10 +-- .../src/__tests__/useRef-test.internal.js | 46 ++++++------ .../__tests__/useSyncExternalStore-test.js | 6 +- .../src/__tests__/ReactFresh-test.js | 6 +- .../__tests__/ReactFreshIntegration-test.js | 2 +- .../ReactFlightDOMRelay-test.internal.js | 4 +- .../src/__tests__/useSubscription-test.js | 56 ++++++++------ 11 files changed, 179 insertions(+), 163 deletions(-) diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js index d3768ff1b14f7..d1f1bc72a9ed4 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js @@ -36,7 +36,7 @@ describe('StrictEffectsMode', () => { ); } - it('should not double invoke effects in legacy mode', () => { + it('should not double invoke effects in legacy mode', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -51,14 +51,14 @@ describe('StrictEffectsMode', () => { return text; } - act(() => { + await act(async () => { ReactTestRenderer.create(); }); assertLog(['useLayoutEffect mount', 'useEffect mount']); }); - it('double invoking for effects works properly', () => { + it('double invoking for effects works properly', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -74,7 +74,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -93,7 +93,7 @@ describe('StrictEffectsMode', () => { assertLog(['useLayoutEffect mount', 'useEffect mount']); } - act(() => { + await act(async () => { renderer.update(); }); @@ -104,14 +104,14 @@ describe('StrictEffectsMode', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { renderer.unmount(); }); assertLog(['useLayoutEffect unmount', 'useEffect unmount']); }); - it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => { + it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect One mount'); @@ -127,7 +127,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -146,7 +146,7 @@ describe('StrictEffectsMode', () => { assertLog(['useEffect One mount', 'useEffect Two mount']); } - act(() => { + await act(async () => { renderer.update(); }); @@ -157,14 +157,14 @@ describe('StrictEffectsMode', () => { 'useEffect Two mount', ]); - act(() => { + await act(async () => { renderer.unmount(null); }); assertLog(['useEffect One unmount', 'useEffect Two unmount']); }); - it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => { + it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => { function App({text}) { React.useLayoutEffect(() => { Scheduler.log('useLayoutEffect One mount'); @@ -180,7 +180,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -199,7 +199,7 @@ describe('StrictEffectsMode', () => { assertLog(['useLayoutEffect One mount', 'useLayoutEffect Two mount']); } - act(() => { + await act(async () => { renderer.update(); }); @@ -210,14 +210,14 @@ describe('StrictEffectsMode', () => { 'useLayoutEffect Two mount', ]); - act(() => { + await act(async () => { renderer.unmount(); }); assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']); }); - it('useEffect and useLayoutEffect is called twice when there is no unmount', () => { + it('useEffect and useLayoutEffect is called twice when there is no unmount', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -231,7 +231,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -248,20 +248,20 @@ describe('StrictEffectsMode', () => { assertLog(['useLayoutEffect mount', 'useEffect mount']); } - act(() => { + await act(async () => { renderer.update(); }); assertLog(['useLayoutEffect mount', 'useEffect mount']); - act(() => { + await act(async () => { renderer.unmount(); }); assertLog([]); }); - it('passes the right context to class component lifecycles', () => { + it('passes the right context to class component lifecycles', async () => { class App extends React.PureComponent { test() {} @@ -285,7 +285,7 @@ describe('StrictEffectsMode', () => { } } - act(() => { + await act(async () => { ReactTestRenderer.create(, {unstable_isConcurrent: true}); }); @@ -300,7 +300,7 @@ describe('StrictEffectsMode', () => { } }); - it('double invoking works for class components', () => { + it('double invoking works for class components', async () => { class App extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -320,7 +320,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -336,20 +336,20 @@ describe('StrictEffectsMode', () => { assertLog(['componentDidMount']); } - act(() => { + await act(async () => { renderer.update(); }); assertLog(['componentDidUpdate']); - act(() => { + await act(async () => { renderer.unmount(); }); assertLog(['componentWillUnmount']); }); - it('should not double invoke class lifecycles in legacy mode', () => { + it('should not double invoke class lifecycles in legacy mode', async () => { class App extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -368,14 +368,14 @@ describe('StrictEffectsMode', () => { } } - act(() => { + await act(async () => { ReactTestRenderer.create(); }); assertLog(['componentDidMount']); }); - it('double flushing passive effects only results in one double invoke', () => { + it('double flushing passive effects only results in one double invoke', async () => { function App({text}) { const [state, setState] = React.useState(0); React.useEffect(() => { @@ -395,7 +395,7 @@ describe('StrictEffectsMode', () => { return text; } - act(() => { + await act(async () => { ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -430,7 +430,7 @@ describe('StrictEffectsMode', () => { } }); - it('newly mounted components after initial mount get double invoked', () => { + it('newly mounted components after initial mount get double invoked', async () => { let _setShowChild; function Child() { React.useEffect(() => { @@ -460,7 +460,7 @@ describe('StrictEffectsMode', () => { return showChild && ; } - act(() => { + await act(async () => { ReactTestRenderer.create(, {unstable_isConcurrent: true}); }); @@ -477,7 +477,7 @@ describe('StrictEffectsMode', () => { assertLog(['App useLayoutEffect mount', 'App useEffect mount']); } - act(() => { + await act(async () => { _setShowChild(true); }); @@ -506,7 +506,7 @@ describe('StrictEffectsMode', () => { } }); - it('classes and functions are double invoked together correctly', () => { + it('classes and functions are double invoked together correctly', async () => { class ClassChild extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -543,7 +543,7 @@ describe('StrictEffectsMode', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -569,7 +569,7 @@ describe('StrictEffectsMode', () => { ]); } - act(() => { + await act(async () => { renderer.update(); }); @@ -580,7 +580,7 @@ describe('StrictEffectsMode', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { renderer.unmount(); }); diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js index 6a428567c4a9e..9a7f736fff91a 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js @@ -37,7 +37,7 @@ describe('StrictEffectsMode defaults', () => { ReactFeatureFlags.createRootStrictEffectsByDefault = __DEV__; }); - it('should not double invoke effects in legacy mode', () => { + it('should not double invoke effects in legacy mode', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -52,14 +52,14 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.renderLegacySyncRoot(); }); assertLog(['useLayoutEffect mount', 'useEffect mount']); }); - it('should not double invoke class lifecycles in legacy mode', () => { + it('should not double invoke class lifecycles in legacy mode', async () => { class App extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -78,7 +78,7 @@ describe('StrictEffectsMode defaults', () => { } } - act(() => { + await act(async () => { ReactNoop.renderLegacySyncRoot(); }); @@ -194,7 +194,7 @@ describe('StrictEffectsMode defaults', () => { }); }); - it('double invoking for effects for modern roots', () => { + it('double invoking for effects for modern roots', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -208,7 +208,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -221,7 +221,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -232,14 +232,14 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { ReactNoop.render(null); }); assertLog(['useLayoutEffect unmount', 'useEffect unmount']); }); - it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => { + it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect One mount'); @@ -254,7 +254,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -267,7 +267,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect Two mount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -278,14 +278,14 @@ describe('StrictEffectsMode defaults', () => { 'useEffect Two mount', ]); - act(() => { + await act(async () => { ReactNoop.render(null); }); assertLog(['useEffect One unmount', 'useEffect Two unmount']); }); - it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => { + it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => { function App({text}) { React.useLayoutEffect(() => { Scheduler.log('useLayoutEffect One mount'); @@ -300,7 +300,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -313,7 +313,7 @@ describe('StrictEffectsMode defaults', () => { 'useLayoutEffect Two mount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -324,14 +324,14 @@ describe('StrictEffectsMode defaults', () => { 'useLayoutEffect Two mount', ]); - act(() => { + await act(async () => { ReactNoop.render(null); }); assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']); }); - it('useEffect and useLayoutEffect is called twice when there is no unmount', () => { + it('useEffect and useLayoutEffect is called twice when there is no unmount', async () => { function App({text}) { React.useEffect(() => { Scheduler.log('useEffect mount'); @@ -344,7 +344,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -355,13 +355,13 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); assertLog(['useLayoutEffect mount', 'useEffect mount']); - act(() => { + await act(async () => { ReactNoop.render(null); }); @@ -369,7 +369,7 @@ describe('StrictEffectsMode defaults', () => { }); //@gate useModernStrictMode - it('disconnects refs during double invoking', () => { + it('disconnects refs during double invoking', async () => { const onRefMock = jest.fn(); function App({text}) { return ( @@ -382,7 +382,7 @@ describe('StrictEffectsMode defaults', () => { ); } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -392,7 +392,7 @@ describe('StrictEffectsMode defaults', () => { expect(onRefMock.mock.calls[2][0]).not.toBeNull(); }); - it('passes the right context to class component lifecycles', () => { + it('passes the right context to class component lifecycles', async () => { class App extends React.PureComponent { test() {} @@ -416,7 +416,7 @@ describe('StrictEffectsMode defaults', () => { } } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -427,7 +427,7 @@ describe('StrictEffectsMode defaults', () => { ]); }); - it('double invoking works for class components', () => { + it('double invoking works for class components', async () => { class App extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -446,7 +446,7 @@ describe('StrictEffectsMode defaults', () => { } } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -456,20 +456,20 @@ describe('StrictEffectsMode defaults', () => { 'componentDidMount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); assertLog(['componentDidUpdate']); - act(() => { + await act(async () => { ReactNoop.render(null); }); assertLog(['componentWillUnmount']); }); - it('double flushing passive effects only results in one double invoke', () => { + it('double flushing passive effects only results in one double invoke', async () => { function App({text}) { const [state, setState] = React.useState(0); React.useEffect(() => { @@ -489,7 +489,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -509,7 +509,7 @@ describe('StrictEffectsMode defaults', () => { ]); }); - it('newly mounted components after initial mount get double invoked', () => { + it('newly mounted components after initial mount get double invoked', async () => { let _setShowChild; function Child() { React.useEffect(() => { @@ -539,7 +539,7 @@ describe('StrictEffectsMode defaults', () => { return showChild && ; } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -552,7 +552,7 @@ describe('StrictEffectsMode defaults', () => { 'App useEffect mount', ]); - act(() => { + await act(async () => { _setShowChild(true); }); @@ -570,7 +570,7 @@ describe('StrictEffectsMode defaults', () => { ]); }); - it('classes and functions are double invoked together correctly', () => { + it('classes and functions are double invoked together correctly', async () => { class ClassChild extends React.PureComponent { componentDidMount() { Scheduler.log('componentDidMount'); @@ -606,7 +606,7 @@ describe('StrictEffectsMode defaults', () => { ); } - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -622,7 +622,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { ReactNoop.render(); }); @@ -633,7 +633,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - act(() => { + await act(async () => { ReactNoop.render(null); }); diff --git a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js index 771042fccace4..6220877d16d9d 100644 --- a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js +++ b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js @@ -604,7 +604,7 @@ describe('useEffectEvent', () => { ReactNoop.render(); await waitForAll(['Effect value: 1', 'Event value: 1']); - act(() => ReactNoop.render()); + await act(async () => ReactNoop.render()); assertLog(['Effect value: 2', 'Event value: 2']); }); @@ -742,52 +742,58 @@ describe('useEffectEvent', () => { return ; } - act(() => ReactNoop.render()); - assertLog(['Welcome to the general room!']); + await act(async () => + ReactNoop.render(), + ); + await act(async () => jest.runAllTimers()); + assertLog(['Welcome to the general room!', 'Connected! theme: light']); expect(ReactNoop).toMatchRenderedOutput( , ); - jest.advanceTimersByTime(100); - Scheduler.unstable_advanceTime(100); - assertLog(['Connected! theme: light']); - // change roomId only - act(() => ReactNoop.render()); - assertLog(['Welcome to the music room!']); + await act(async () => + ReactNoop.render(), + ); + await act(async () => jest.runAllTimers()); + assertLog([ + 'Welcome to the music room!', + // should trigger a reconnect + 'Connected! theme: light', + ]); + expect(ReactNoop).toMatchRenderedOutput( , ); - jest.advanceTimersByTime(100); - Scheduler.unstable_advanceTime(100); - // should trigger a reconnect - assertLog(['Connected! theme: light']); // change theme only - act(() => ReactNoop.render()); + await act(async () => + ReactNoop.render(), + ); + await act(async () => jest.runAllTimers()); + // should not trigger a reconnect assertLog(['Welcome to the music room!']); expect(ReactNoop).toMatchRenderedOutput( , ); - jest.advanceTimersByTime(100); - Scheduler.unstable_advanceTime(100); - // should not trigger a reconnect - await waitForAll([]); // change roomId only - act(() => ReactNoop.render()); - assertLog(['Welcome to the travel room!']); + await act(async () => + ReactNoop.render(), + ); + await act(async () => jest.runAllTimers()); + assertLog([ + 'Welcome to the travel room!', + // should trigger a reconnect + 'Connected! theme: dark', + ]); expect(ReactNoop).toMatchRenderedOutput( , ); - jest.advanceTimersByTime(100); - Scheduler.unstable_advanceTime(100); - // should trigger a reconnect - assertLog(['Connected! theme: dark']); }); // @gate enableUseEffectEventHook - it('integration: implements the docs logVisit example', () => { + it('integration: implements the docs logVisit example', async () => { class AddToCartButton extends React.PureComponent { addToCart = () => { this.props.onClick(); @@ -835,7 +841,7 @@ describe('useEffectEvent', () => { } const button = React.createRef(null); - act(() => + await act(async () => ReactNoop.render( @@ -846,7 +852,7 @@ describe('useEffectEvent', () => { act(button.current.addToCart); assertLog(['Add to cart']); - act(() => + await act(async () => ReactNoop.render( diff --git a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js index de3085de0e8fe..a5d9391c668fc 100644 --- a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js @@ -1666,7 +1666,7 @@ describe('useMutableSource', () => { } // Mount ComponentA with data version 1 - act(() => { + await act(async () => { ReactNoop.render( @@ -1703,7 +1703,7 @@ describe('useMutableSource', () => { if (__DEV__) { describe('dev warnings', () => { // @gate enableUseMutableSource - it('should warn if the subscribe function does not return an unsubscribe function', () => { + it('should warn if the subscribe function does not return an unsubscribe function', async () => { const source = createSource('one'); const mutableSource = createMutableSource( source, @@ -1712,8 +1712,8 @@ describe('useMutableSource', () => { const brokenSubscribe = () => {}; - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactNoop.render( { } // @gate enableUseMutableSource - it('should render and hydrate', () => { + it('should render and hydrate', async () => { const source = createSource('one'); const mutableSource = createMutableSource(source, param => param.version); @@ -165,7 +165,7 @@ describe('useMutableSourceHydration', () => { assertLog(['only:one']); expect(source.listenerCount).toBe(0); - act(() => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { mutableSources: [mutableSource], }); @@ -176,7 +176,7 @@ describe('useMutableSourceHydration', () => { // @gate enableUseMutableSource // @gate enableClientRenderFallbackOnTextMismatch - it('should detect a tear before hydrating a component', () => { + it('should detect a tear before hydrating a component', async () => { const source = createSource('one'); const mutableSource = createMutableSource(source, param => param.version); @@ -199,8 +199,8 @@ describe('useMutableSourceHydration', () => { assertLog(['only:one']); expect(source.listenerCount).toBe(0); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { mutableSources: [mutableSource], onRecoverableError(error) { diff --git a/packages/react-reconciler/src/__tests__/useRef-test.internal.js b/packages/react-reconciler/src/__tests__/useRef-test.internal.js index ab5635b3c2457..805b27e58c3f9 100644 --- a/packages/react-reconciler/src/__tests__/useRef-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useRef-test.internal.js @@ -50,7 +50,7 @@ describe('useRef', () => { return ; } - it('creates a ref object initialized with the provided value', () => { + it('creates a ref object initialized with the provided value', async () => { jest.useFakeTimers(); function useDebouncedCallback(callback, ms, inputs) { @@ -82,7 +82,7 @@ describe('useRef', () => { return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); assertLog([]); @@ -134,7 +134,7 @@ describe('useRef', () => { }); if (__DEV__) { - it('should never warn when attaching to children', () => { + it('should never warn when attaching to children', async () => { class Component extends React.Component { render() { return null; @@ -152,16 +152,16 @@ describe('useRef', () => { ); } - act(() => { + await act(async () => { ReactNoop.render(); }); - act(() => { + await act(async () => { ReactNoop.render(); }); }); // @gate enableUseRefAccessWarning - it('should warn about reads during render', () => { + it('should warn about reads during render', async () => { function Example() { const ref = useRef(123); let value; @@ -173,12 +173,12 @@ describe('useRef', () => { return value; } - act(() => { + await act(async () => { ReactNoop.render(); }); }); - it('should not warn about lazy init during render', () => { + it('should not warn about lazy init during render', async () => { function Example() { const ref1 = useRef(null); const ref2 = useRef(undefined); @@ -192,17 +192,17 @@ describe('useRef', () => { return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); // Should not warn after an update either. - act(() => { + await act(async () => { ReactNoop.render(); }); }); - it('should not warn about lazy init outside of render', () => { + it('should not warn about lazy init outside of render', async () => { function Example() { // eslint-disable-next-line no-unused-vars const [didMount, setDidMount] = useState(false); @@ -216,13 +216,13 @@ describe('useRef', () => { return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); }); // @gate enableUseRefAccessWarning - it('should warn about unconditional lazy init during render', () => { + it('should warn about unconditional lazy init during render', async () => { function Example() { const ref1 = useRef(null); const ref2 = useRef(undefined); @@ -251,19 +251,19 @@ describe('useRef', () => { } let shouldExpectWarning = true; - act(() => { + await act(async () => { ReactNoop.render(); }); // Should not warn again on update. shouldExpectWarning = false; - act(() => { + await act(async () => { ReactNoop.render(); }); }); // @gate enableUseRefAccessWarning - it('should warn about reads to ref after lazy init pattern', () => { + it('should warn about reads to ref after lazy init pattern', async () => { function Example() { const ref1 = useRef(null); const ref2 = useRef(undefined); @@ -291,13 +291,13 @@ describe('useRef', () => { return value; } - act(() => { + await act(async () => { ReactNoop.render(); }); }); // @gate enableUseRefAccessWarning - it('should warn about writes to ref after lazy init pattern', () => { + it('should warn about writes to ref after lazy init pattern', async () => { function Example() { const ref1 = useRef(null); const ref2 = useRef(undefined); @@ -323,12 +323,12 @@ describe('useRef', () => { return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); }); - it('should not warn about reads or writes within effect', () => { + it('should not warn about reads or writes within effect', async () => { function Example() { const ref = useRef(123); useLayoutEffect(() => { @@ -344,21 +344,21 @@ describe('useRef', () => { return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); ReactNoop.flushPassiveEffects(); }); - it('should not warn about reads or writes outside of render phase (e.g. event handler)', () => { + it('should not warn about reads or writes outside of render phase (e.g. event handler)', async () => { let ref; function Example() { ref = useRef(123); return null; } - act(() => { + await act(async () => { ReactNoop.render(); }); diff --git a/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js b/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js index 96f9c2a292aa7..9e371268c404c 100644 --- a/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js +++ b/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js @@ -195,19 +195,19 @@ describe('useSyncExternalStore', () => { } const root = ReactNoop.createRoot(); - act(() => { + await act(async () => { // Start a render that reads from the store and yields value root.render(); }); assertLog(['value:initial']); - await act(() => { + await act(async () => { store.set('value:changed'); }); assertLog(['value:changed']); // If cached value was updated, we expect a re-render - await act(() => { + await act(async () => { store.set('value:initial'); }); assertLog(['value:initial']); diff --git a/packages/react-refresh/src/__tests__/ReactFresh-test.js b/packages/react-refresh/src/__tests__/ReactFresh-test.js index 618e46d6fe34d..0c88a9c0ac06a 100644 --- a/packages/react-refresh/src/__tests__/ReactFresh-test.js +++ b/packages/react-refresh/src/__tests__/ReactFresh-test.js @@ -17,6 +17,7 @@ let ReactDOMClient; let ReactFreshRuntime; let Scheduler; let act; +let internalAct; let createReactClass; let waitFor; let assertLog; @@ -33,7 +34,8 @@ describe('ReactFresh', () => { ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); Scheduler = require('scheduler'); - act = require('jest-react').act; + act = require('react-dom/test-utils').act; + internalAct = require('jest-react').act; const InternalTestUtils = require('internal-test-utils'); waitFor = InternalTestUtils.waitFor; @@ -2480,7 +2482,7 @@ describe('ReactFresh', () => { expect(el.firstChild.textContent).toBe('0'); expect(el.firstChild.style.color).toBe('red'); - await act(async () => { + await internalAct(async () => { el.firstChild.dispatchEvent( new MouseEvent('click', { bubbles: true, diff --git a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js index ad963c056990e..54e596f6232c3 100644 --- a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js +++ b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js @@ -31,7 +31,7 @@ describe('ReactFreshIntegration', () => { ReactFreshRuntime = require('react-refresh/runtime'); ReactFreshRuntime.injectIntoGlobalHook(global); ReactDOM = require('react-dom'); - act = require('jest-react').act; + act = require('react-dom/test-utils').act; container = document.createElement('div'); document.body.appendChild(container); exportsObj = undefined; diff --git a/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js b/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js index 74b9bab83a4d9..c42757b481cc2 100644 --- a/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js +++ b/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js @@ -85,7 +85,7 @@ describe('ReactFlightDOMRelay', () => { }); }); - it('can render a Client Component using a module reference and render there', () => { + it('can render a Client Component using a module reference and render there', async () => { function UserClient(props) { return ( @@ -110,7 +110,7 @@ describe('ReactFlightDOMRelay', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { root.render(modelClient.greeting); }); diff --git a/packages/use-subscription/src/__tests__/useSubscription-test.js b/packages/use-subscription/src/__tests__/useSubscription-test.js index 89bf30a7fa2b5..aa4aa5cd0b8c7 100644 --- a/packages/use-subscription/src/__tests__/useSubscription-test.js +++ b/packages/use-subscription/src/__tests__/useSubscription-test.js @@ -81,7 +81,7 @@ describe('useSubscription', () => { const observable = createBehaviorSubject(); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, @@ -90,14 +90,14 @@ describe('useSubscription', () => { assertLog(['default']); // Updates while subscribed should re-render the child component - act(() => observable.next(123)); + await act(async () => observable.next(123)); assertLog([123]); - act(() => observable.next('abc')); + await act(async () => observable.next('abc')); assertLog(['abc']); // Unmounting the subscriber should remove listeners - act(() => renderer.update(
)); - act(() => observable.next(456)); + await act(async () => renderer.update(
)); + await act(async () => observable.next(456)); await waitForAll([]); }); @@ -133,21 +133,23 @@ describe('useSubscription', () => { let observable = createReplaySubject('initial'); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, ); }); assertLog(['initial']); - act(() => observable.next('updated')); + await act(async () => observable.next('updated')); assertLog(['updated']); await waitForAll([]); // Unsetting the subscriber prop should reset subscribed values observable = createReplaySubject(undefined); - act(() => renderer.update()); + await act(async () => + renderer.update(), + ); assertLog(['default']); }); @@ -182,7 +184,7 @@ describe('useSubscription', () => { expect(subscriptions).toHaveLength(0); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, @@ -195,18 +197,20 @@ describe('useSubscription', () => { expect(subscriptions[0]).toBe(observableA); // Unsetting the subscriber prop should reset subscribed values - act(() => renderer.update()); + await act(async () => + renderer.update(), + ); assertLog(['b-0']); expect(subscriptions).toHaveLength(2); expect(subscriptions[1]).toBe(observableB); // Updates to the old subscribable should not re-render the child component - act(() => observableA.next('a-1')); + await act(async () => observableA.next('a-1')); await waitForAll([]); // Updates to the bew subscribable should re-render the child component - act(() => observableB.next('b-1')); + await act(async () => observableB.next('b-1')); assertLog(['b-1']); expect(subscriptions).toHaveLength(2); @@ -241,7 +245,7 @@ describe('useSubscription', () => { expect(subscriptions).toHaveLength(0); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, @@ -254,17 +258,19 @@ describe('useSubscription', () => { expect(subscriptions[0]).toBe(observableA); // Unsetting the subscriber prop should reset subscribed values - act(() => renderer.update()); + await act(async () => + renderer.update(), + ); assertLog(['b-0']); expect(subscriptions).toHaveLength(2); expect(subscriptions[1]).toBe(observableB); // Updates to the old subscribable should not re-render the child component - act(() => observableA.next('a-1')); + await act(async () => observableA.next('a-1')); await waitForAll([]); // Updates to the bew subscribable should re-render the child component - act(() => observableB.next('b-1')); + await act(async () => observableB.next('b-1')); assertLog(['b-1']); expect(subscriptions).toHaveLength(2); @@ -329,7 +335,7 @@ describe('useSubscription', () => { const observableB = createBehaviorSubject('b-0'); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -353,7 +359,7 @@ describe('useSubscription', () => { }); // Update again - act(() => renderer.update()); + await act(async () => renderer.update()); // Flush everything and ensure that the correct subscribable is used // We expect the last emitted update to be rendered (because of the commit phase value check) @@ -432,7 +438,7 @@ describe('useSubscription', () => { const observableB = createBehaviorSubject('b-0'); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(, { unstable_isConcurrent: true, }); @@ -474,12 +480,12 @@ describe('useSubscription', () => { // Updates from the new subscribable should be ignored. log.splice(0); - act(() => observableB.next('b-1')); + await act(async () => observableB.next('b-1')); await waitForAll([]); expect(log).toEqual([]); }); - it('should guard against updates that happen after unmounting', () => { + it('should guard against updates that happen after unmounting', async () => { function Child({value = 'default'}) { Scheduler.log(value); return null; @@ -529,7 +535,7 @@ describe('useSubscription', () => { }); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, @@ -563,7 +569,7 @@ describe('useSubscription', () => { } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( , {unstable_isConcurrent: true}, @@ -571,7 +577,9 @@ describe('useSubscription', () => { }); await waitForAll([]); - act(() => renderer.update()); + await act(async () => + renderer.update(), + ); await waitForAll([]); });