From 3ff151daddb04ffaefe256d3cd5ccefd96f623ce Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 7 Apr 2020 16:40:41 -0700 Subject: [PATCH 1/2] Add another test for #18515 using pings Adds a regression test for the same underlying bug as #18515 but using pings. Test already passes, but I confirmed it fails if you revert the fix in #18515. --- ...tSuspenseWithNoopRenderer-test.internal.js | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 966fc653ca127..d27b422f46c58 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -3645,4 +3645,117 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); }); + + it('regression: ping at high priority causes update to be dropped', async () => { + const {useState, useTransition} = React; + + let setTextA; + function A() { + const [textA, _setTextA] = useState('A'); + setTextA = _setTextA; + return ( + }> + + + ); + } + + let setTextB; + let startTransition; + function B() { + const [textB, _setTextB] = useState('B'); + const [_startTransition] = useTransition({timeoutMs: 10000}); + startTransition = _startTransition; + setTextB = _setTextB; + return ( + }> + + + ); + } + + function App() { + return ( + <> + + + + ); + } + + const root = ReactNoop.createRoot(); + await ReactNoop.act(async () => { + await resolveText('A'); + await resolveText('B'); + root.render(); + }); + expect(Scheduler).toHaveYielded(['A', 'B']); + expect(root).toMatchRenderedOutput( + <> + + + , + ); + + await ReactNoop.act(async () => { + // Triggers suspense at normal pri + setTextA('A1'); + // Triggers in an unrelated tree at a different pri + startTransition(() => { + // Update A again so that it doesn't suspend on A1. That way we can ping + // the A1 update without also pinging this one. This is a workaround + // because there's currently no way to render at a lower priority (B2) + // without including all updates at higher priority (A1). + setTextA('A2'); + setTextB('B2'); + }); + }); + expect(Scheduler).toHaveYielded([ + 'B', + 'Suspend! [A1]', + 'Loading...', + + 'Suspend! [A2]', + 'Loading...', + 'Suspend! [B2]', + 'Loading...', + ]); + expect(root).toMatchRenderedOutput( + <> + + + , + ); + + await ReactNoop.act(async () => { + resolveText('A1'); + }); + expect(Scheduler).toHaveYielded([ + 'Promise resolved [A1]', + 'A1', + 'Suspend! [A2]', + 'Loading...', + 'Suspend! [B2]', + 'Loading...', + ]); + expect(root).toMatchRenderedOutput( + <> + + + , + ); + + // Commit the placeholder + Scheduler.unstable_advanceTime(20000); + await advanceTimers(20000); + + expect(root).toMatchRenderedOutput( + <> +