diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js index 43ec803f11555..8d006b2f300bc 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js @@ -3416,4 +3416,60 @@ describe('ReactHooksWithNoopRenderer', () => { 'Unmount A', ]); }); + + // @gate experimental + it('regression: SuspenseList causes unmounts to be dropped on deletion', async () => { + const SuspenseList = React.unstable_SuspenseList; + + function Row({label}) { + useEffect(() => { + Scheduler.unstable_yieldValue('Mount ' + label); + return () => { + Scheduler.unstable_yieldValue('Unmount ' + label); + }; + }, [label]); + return ( + + + + ); + } + + function App() { + return ( + + + + + ); + } + + const root = ReactNoop.createRoot(); + await ReactNoop.act(async () => { + root.render(); + }); + expect(Scheduler).toHaveYielded([ + 'Suspend! [A]', + 'Suspend! [B]', + 'Mount A', + 'Mount B', + ]); + + await ReactNoop.act(async () => { + await resolveText('A'); + }); + expect(Scheduler).toHaveYielded([ + 'Promise resolved [A]', + 'A', + 'Suspend! [B]', + ]); + + await ReactNoop.act(async () => { + root.render(null); + }); + // In the regression, SuspenseList would cause the children to "forget" that + // it contains passive effects. Then when we deleted the tree, these unmount + // effects would not fire. + expect(Scheduler).toHaveYielded(['Unmount A', 'Unmount B']); + }); });