Skip to content

Commit b225cc1

Browse files
committed
Test unblocking with a high-pri update
1 parent 19315d2 commit b225cc1

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3409,4 +3409,108 @@ describe('ReactSuspenseWithNoopRenderer', () => {
34093409
);
34103410
},
34113411
);
3412+
3413+
it('a high pri update can unhide a boundary that suspended at a different level', async () => {
3414+
const {useState, useEffect} = React;
3415+
const root = ReactNoop.createRoot();
3416+
3417+
let setOuterText;
3418+
function Parent({step}) {
3419+
const [text, _setText] = useState('A');
3420+
setOuterText = _setText;
3421+
return (
3422+
<>
3423+
<Text text={'Outer: ' + text + step} />
3424+
<Suspense fallback={<Text text="Loading..." />}>
3425+
<Child step={step} outerText={text} />
3426+
</Suspense>
3427+
</>
3428+
);
3429+
}
3430+
3431+
let setInnerText;
3432+
function Child({step, outerText}) {
3433+
const [text, _setText] = useState('A');
3434+
setInnerText = _setText;
3435+
3436+
// This will log if the component commits in an inconsistent state
3437+
useEffect(() => {
3438+
if (text === outerText) {
3439+
Scheduler.unstable_yieldValue('Commit Child');
3440+
} else {
3441+
Scheduler.unstable_yieldValue(
3442+
'FIXME: Texts are inconsistent (tearing)',
3443+
);
3444+
}
3445+
}, [text, outerText]);
3446+
3447+
return (
3448+
<>
3449+
<AsyncText text={'Inner: ' + text + step} />
3450+
</>
3451+
);
3452+
}
3453+
3454+
// These always update simultaneously. They must be consistent.
3455+
function setText(text) {
3456+
setOuterText(text);
3457+
setInnerText(text);
3458+
}
3459+
3460+
// Mount an initial tree. Resolve A so that it doesn't suspend.
3461+
await resolveText('Inner: A0');
3462+
await ReactNoop.act(async () => {
3463+
root.render(<Parent step={0} />);
3464+
});
3465+
expect(Scheduler).toHaveYielded(['Outer: A0', 'Inner: A0', 'Commit Child']);
3466+
expect(root).toMatchRenderedOutput(
3467+
<>
3468+
<span prop="Outer: A0" />
3469+
<span prop="Inner: A0" />
3470+
</>,
3471+
);
3472+
3473+
// Update. This causes the inner component to suspend.
3474+
await ReactNoop.act(async () => {
3475+
setText('B');
3476+
});
3477+
expect(Scheduler).toHaveYielded([
3478+
'Outer: B0',
3479+
'Suspend! [Inner: B0]',
3480+
'Loading...',
3481+
]);
3482+
// Commit the placeholder
3483+
await advanceTimers(250);
3484+
expect(root).toMatchRenderedOutput(
3485+
<>
3486+
<span prop="Outer: B0" />
3487+
<span hidden={true} prop="Inner: A0" />
3488+
<span prop="Loading..." />
3489+
</>,
3490+
);
3491+
3492+
// Schedule a high pri update on the parent. This will unblock the content.
3493+
await resolveText('Inner: B1');
3494+
await ReactNoop.act(async () => {
3495+
ReactNoop.discreteUpdates(() => {
3496+
root.render(<Parent step={1} />);
3497+
});
3498+
});
3499+
3500+
expect(Scheduler).toHaveYielded([
3501+
// First the outer part of the tree updates, at high pri.
3502+
'Outer: B1',
3503+
'Loading...',
3504+
3505+
// Then we retry the boundary.
3506+
'Inner: B1',
3507+
'Commit Child',
3508+
]);
3509+
expect(root).toMatchRenderedOutput(
3510+
<>
3511+
<span prop="Outer: B1" />
3512+
<span prop="Inner: B1" />
3513+
</>,
3514+
);
3515+
});
34123516
});

0 commit comments

Comments
 (0)