let React; let ReactNoop; let Scheduler; let act; let LegacyHidden; let Activity; let useState; let useLayoutEffect; let useEffect; let useInsertionEffect; let useMemo; let startTransition; let waitForPaint; let waitFor; let assertLog; let assertConsoleErrorDev; let Suspense; describe('Activity', () => { beforeEach(() => { jest.resetModules(); React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); act = require('internal-test-utils').act; LegacyHidden = React.unstable_LegacyHidden; Activity = React.Activity; Suspense = React.Suspense; useState = React.useState; useInsertionEffect = React.useInsertionEffect; useLayoutEffect = React.useLayoutEffect; useEffect = React.useEffect; useMemo = React.useMemo; startTransition = React.startTransition; const InternalTestUtils = require('internal-test-utils'); waitForPaint = InternalTestUtils.waitForPaint; waitFor = InternalTestUtils.waitFor; assertLog = InternalTestUtils.assertLog; assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev; }); function Text(props) { Scheduler.log(props.text); return {props.children}; } // @gate enableLegacyHidden it('unstable-defer-without-hiding should never toggle the visibility of its children', async () => { function App({mode}) { return ( <> ); } // Test the initial mount const root = ReactNoop.createRoot(); await act(async () => { root.render(); await waitForPaint(['Normal']); expect(root).toMatchRenderedOutput(); }); assertLog(['Deferred']); expect(root).toMatchRenderedOutput( <> , ); // Now try after an update await act(() => { root.render(); }); assertLog(['Normal', 'Deferred']); expect(root).toMatchRenderedOutput( <> , ); await act(async () => { root.render(); await waitForPaint(['Normal']); expect(root).toMatchRenderedOutput( <> , ); }); assertLog(['Deferred']); expect(root).toMatchRenderedOutput( <> , ); }); // @gate enableLegacyHidden && !disableLegacyMode it('does not defer in legacy mode', async () => { let setState; function Foo() { const [state, _setState] = useState('A'); setState = _setState; return ; } const root = ReactNoop.createLegacyRoot(); await act(() => { root.render( <> , ); ReactNoop.flushSync(); // Should not defer the hidden tree assertLog(['A', 'Outside']); }); expect(root).toMatchRenderedOutput( <> , ); // Test that the children can be updated await act(() => { setState('B'); }); assertLog(['B']); expect(root).toMatchRenderedOutput( <> , ); }); // @gate enableLegacyHidden it('does defer in concurrent mode', async () => { let setState; function Foo() { const [state, _setState] = useState('A'); setState = _setState; return ; } const root = ReactNoop.createRoot(); await act(async () => { root.render( <> , ); // Should defer the hidden tree. await waitForPaint(['Outside']); }); // The hidden tree was rendered at lower priority. assertLog(['A']); expect(root).toMatchRenderedOutput( <> , ); // Test that the children can be updated await act(() => { setState('B'); }); assertLog(['B']); expect(root).toMatchRenderedOutput( <> , ); }); it('mounts without layout effects when hidden', async () => { function Child({text}) { useLayoutEffect(() => { Scheduler.log('Mount layout'); return () => { Scheduler.log('Unmount layout'); }; }, []); return ; } const root = ReactNoop.createRoot(); // Mount hidden tree. await act(() => { root.render( , ); }); // No layout effect. assertLog(['Child']); expect(root).toMatchRenderedOutput(