Clean up enableSiblingPrerendering flag (#32319)

This commit is contained in:
Jack Pope 2025-05-08 20:49:23 -04:00 committed by GitHub
parent 9b79292ae7
commit 4ca97e4891
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 865 additions and 1177 deletions

View File

@ -126,8 +126,8 @@ describe('ReactCache', () => {
await waitForAll([
'Suspend! [Hi]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Hi]'] : []),
// pre-warming
'Suspend! [Hi]',
]);
jest.advanceTimersByTime(100);
@ -150,8 +150,8 @@ describe('ReactCache', () => {
await waitForAll([
'Suspend! [Hi]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Hi]'] : []),
// pre-warming
'Suspend! [Hi]',
]);
textResourceShouldFail = true;
@ -195,8 +195,8 @@ describe('ReactCache', () => {
await waitForAll([
'App',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['App'] : []),
// pre-warming
'App',
]);
assertConsoleErrorDev([
'Invalid key type. Expected a string, number, symbol, or ' +
@ -204,27 +204,24 @@ describe('ReactCache', () => {
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' +
' in App (at **)',
...(gate('enableSiblingPrerendering')
? [
'Invalid key type. Expected a string, number, symbol, or ' +
"boolean, but instead received: [ 'Hi', 100 ]\n\n" +
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' +
' in App (at **)',
]
: []),
// pre-warming
'Invalid key type. Expected a string, number, symbol, or ' +
"boolean, but instead received: [ 'Hi', 100 ]\n\n" +
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' +
' in App (at **)',
]);
} else {
await waitForAll([
'App',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['App'] : []),
// pre-warming
'App',
]);
}
});
// @gate enableSiblingPrerendering
it('evicts least recently used values', async () => {
ReactCache.unstable_setGlobalCacheLimit(3);
@ -240,15 +237,28 @@ describe('ReactCache', () => {
await waitForPaint(['Suspend! [1]', 'Loading...']);
jest.advanceTimersByTime(100);
assertLog(['Promise resolved [1]']);
await waitForAll([1, 'Suspend! [2]']);
await waitForAll([
1,
'Suspend! [2]',
...(gate('alwaysThrottleRetries')
? []
: [1, 'Suspend! [2]', 'Suspend! [3]']),
]);
jest.advanceTimersByTime(100);
assertLog(['Promise resolved [2]']);
await waitForAll([1, 2, 'Suspend! [3]']);
assertLog([
'Promise resolved [2]',
...(gate('alwaysThrottleRetries') ? [] : ['Promise resolved [3]']),
]);
await waitForAll([
1,
2,
...(gate('alwaysThrottleRetries') ? ['Suspend! [3]'] : [3]),
]);
jest.advanceTimersByTime(100);
assertLog(['Promise resolved [3]']);
await waitForAll([1, 2, 3]);
assertLog(gate('alwaysThrottleRetries') ? ['Promise resolved [3]'] : []);
await waitForAll(gate('alwaysThrottleRetries') ? [1, 2, 3] : []);
await act(() => jest.advanceTimersByTime(100));
expect(root).toMatchRenderedOutput('123');
@ -378,8 +388,8 @@ describe('ReactCache', () => {
await waitForAll([
'Suspend! [Hi]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Hi]'] : []),
// pre-warming
'Suspend! [Hi]',
]);
resolveThenable('Hi');

View File

@ -15,22 +15,11 @@ import {
normalizeCodeLocInfo,
} from './utils';
import {ReactVersion} from '../../../../ReactVersions';
import semver from 'semver';
let React = require('react');
let Scheduler;
let store;
let utils;
// TODO: This is how other DevTools tests access the version but we should find
// a better solution for this
const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion;
// Disabling this while the flag is off in experimental. Leaving the logic so we can
// restore the behavior when we turn the flag back on.
const enableSiblingPrerendering =
false && semver.gte(ReactVersionTestingAgainst, '19.0.0');
// This flag is on experimental which disables timeline profiler.
const enableComponentPerformanceTrack =
React.version.startsWith('19') && React.version.includes('experimental');
@ -1678,8 +1667,8 @@ describe('Timeline profiler', () => {
await waitForAll([
'suspended',
...(enableSiblingPrerendering ? ['suspended'] : []),
// pre-warming
'suspended',
]);
Scheduler.unstable_advanceTime(10);
@ -1691,8 +1680,7 @@ describe('Timeline profiler', () => {
const timelineData = stopProfilingAndGetTimelineData();
// Verify the Suspense event and duration was recorded.
if (enableSiblingPrerendering) {
expect(timelineData.suspenseEvents).toMatchInlineSnapshot(`
expect(timelineData.suspenseEvents).toMatchInlineSnapshot(`
[
{
"componentName": "Example",
@ -1720,29 +1708,11 @@ describe('Timeline profiler', () => {
},
]
`);
} else {
const suspenseEvent = timelineData.suspenseEvents[0];
expect(suspenseEvent).toMatchInlineSnapshot(`
{
"componentName": "Example",
"depth": 0,
"duration": 10,
"id": "0",
"phase": "mount",
"promiseName": "",
"resolution": "resolved",
"timestamp": 10,
"type": "suspense",
"warning": null,
}
`);
}
// There should be two batches of renders: Suspeneded and resolved.
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
expect(timelineData.componentMeasures).toHaveLength(
enableSiblingPrerendering ? 3 : 2,
);
// An additional measure with pre-warming
expect(timelineData.componentMeasures).toHaveLength(3);
});
it('should mark concurrent render with suspense that rejects', async () => {
@ -1769,11 +1739,7 @@ describe('Timeline profiler', () => {
</React.Suspense>,
);
await waitForAll([
'suspended',
...(enableSiblingPrerendering ? ['suspended'] : []),
]);
await waitForAll(['suspended', 'suspended']);
Scheduler.unstable_advanceTime(10);
rejectFn();
@ -1784,8 +1750,7 @@ describe('Timeline profiler', () => {
const timelineData = stopProfilingAndGetTimelineData();
// Verify the Suspense event and duration was recorded.
if (enableSiblingPrerendering) {
expect(timelineData.suspenseEvents).toMatchInlineSnapshot(`
expect(timelineData.suspenseEvents).toMatchInlineSnapshot(`
[
{
"componentName": "Example",
@ -1813,30 +1778,11 @@ describe('Timeline profiler', () => {
},
]
`);
} else {
expect(timelineData.suspenseEvents).toHaveLength(1);
const suspenseEvent = timelineData.suspenseEvents[0];
expect(suspenseEvent).toMatchInlineSnapshot(`
{
"componentName": "Example",
"depth": 0,
"duration": 10,
"id": "0",
"phase": "mount",
"promiseName": "",
"resolution": "rejected",
"timestamp": 10,
"type": "suspense",
"warning": null,
}
`);
}
// There should be two batches of renders: Suspeneded and resolved.
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
expect(timelineData.componentMeasures).toHaveLength(
enableSiblingPrerendering ? 3 : 2,
);
// An additional measure with pre-warming
expect(timelineData.componentMeasures).toHaveLength(3);
});
it('should mark cascading class component state updates', async () => {

View File

@ -751,7 +751,8 @@ describe('ReactDOMFiberAsync', () => {
// Because it suspended, it remains on the current path
expect(div.textContent).toBe('/path/a');
});
assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []);
// pre-warming
assertLog(['Suspend! [/path/b]']);
await act(async () => {
resolvePromise();

View File

@ -1437,8 +1437,8 @@ describe('ReactDOMForm', () => {
assertLog([
'Suspend! [Count: 0]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Count: 0]'] : []),
// pre-warming
'Suspend! [Count: 0]',
]);
await act(() => resolveText('Count: 0'));
assertLog(['Count: 0']);
@ -1448,8 +1448,8 @@ describe('ReactDOMForm', () => {
assertLog([
'Suspend! [Count: 1]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Count: 1]'] : []),
// pre-warming
'Suspend! [Count: 1]',
]);
expect(container.textContent).toBe('Loading...');
@ -1482,8 +1482,8 @@ describe('ReactDOMForm', () => {
await act(() => root.render(<App />));
assertLog([
'Suspend! [Count: 0]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Count: 0]'] : []),
// pre-warming
'Suspend! [Count: 0]',
]);
await act(() => resolveText('Count: 0'));
assertLog(['Count: 0']);
@ -1501,8 +1501,8 @@ describe('ReactDOMForm', () => {
]);
assertLog([
'Suspend! [Count: 1]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Count: 1]'] : []),
// pre-warming
'Suspend! [Count: 1]',
]);
expect(container.textContent).toBe('Count: 0');
});

View File

@ -164,8 +164,10 @@ describe('ReactDOMSuspensePlaceholder', () => {
'A',
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [B]', 'C'] : []),
// pre-warming
'A',
'Suspend! [B]',
'C',
]);
await act(() => {
resolveText('B');

View File

@ -196,8 +196,8 @@ test('regression (#20932): return pointer is correct before entering deleted tre
'Suspend! [0]',
'Loading Async...',
'Loading Tail...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [0]'] : []),
// pre-warming
'Suspend! [0]',
]);
await act(() => {
resolveText(0);
@ -211,7 +211,7 @@ test('regression (#20932): return pointer is correct before entering deleted tre
'Loading Async...',
'Suspend! [1]',
'Loading Async...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [1]'] : []),
// pre-warming
'Suspend! [1]',
]);
});

View File

@ -41,7 +41,6 @@ import {
enableRenderableContext,
passChildrenWhenCloningPersistedNodes,
disableLegacyMode,
enableSiblingPrerendering,
enableViewTransition,
enableSuspenseyImages,
} from 'shared/ReactFeatureFlags';
@ -667,9 +666,7 @@ function scheduleRetryEffect(
// Track the lanes that have been scheduled for an immediate retry so that
// we can mark them as suspended upon committing the root.
if (enableSiblingPrerendering) {
markSpawnedRetryLane(retryLane);
}
markSpawnedRetryLane(retryLane);
}
}

View File

@ -27,7 +27,6 @@ import {
transitionLaneExpirationMs,
retryLaneExpirationMs,
disableLegacyMode,
enableSiblingPrerendering,
} from 'shared/ReactFeatureFlags';
import {isDevToolsPresent} from './ReactFiberDevToolsHook';
import {clz32} from './clz32';
@ -267,13 +266,11 @@ export function getNextLanes(
if (nonIdlePingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);
} else {
if (enableSiblingPrerendering) {
// Nothing has been pinged. Check for lanes that need to be prewarmed.
if (!rootHasPendingCommit) {
const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
// Nothing has been pinged. Check for lanes that need to be prewarmed.
if (!rootHasPendingCommit) {
const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
}
}
@ -293,13 +290,11 @@ export function getNextLanes(
if (pingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(pingedLanes);
} else {
if (enableSiblingPrerendering) {
// Nothing has been pinged. Check for lanes that need to be prewarmed.
if (!rootHasPendingCommit) {
const lanesToPrewarm = pendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
// Nothing has been pinged. Check for lanes that need to be prewarmed.
if (!rootHasPendingCommit) {
const lanesToPrewarm = pendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
}
}
@ -802,7 +797,7 @@ export function markRootSuspended(
root.suspendedLanes |= suspendedLanes;
root.pingedLanes &= ~suspendedLanes;
if (enableSiblingPrerendering && didAttemptEntireTree) {
if (didAttemptEntireTree) {
// Mark these lanes as warm so we know there's nothing else to work on.
root.warmLanes |= suspendedLanes;
} else {
@ -913,7 +908,6 @@ export function markRootFinished(
// suspended) instead of the regular mode (i.e. unwind and skip the siblings
// as soon as something suspends to unblock the rest of the update).
if (
enableSiblingPrerendering &&
suspendedRetryLanes !== NoLanes &&
// Note that we only do this if there were no updates since we started
// rendering. This mirrors the logic in markRootUpdated — whenever we

View File

@ -18,7 +18,6 @@ import {
enableProfilerTimer,
enableProfilerNestedUpdatePhase,
enableComponentPerformanceTrack,
enableSiblingPrerendering,
enableYieldingBeforePassive,
enableGestureTransition,
} from 'shared/ReactFeatureFlags';
@ -381,7 +380,7 @@ function scheduleTaskForRootDuringMicrotask(
// If we're prerendering, then we should use the concurrent work loop
// even if the lanes are synchronous, so that prerendering never blocks
// the main thread.
!(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes))
!checkIfRootIsPrerendering(root, nextLanes)
) {
// Synchronous work is always flushed at the end of the microtask, so we
// don't need to schedule an additional task.

View File

@ -47,7 +47,6 @@ import {
enableInfiniteRenderLoopDetection,
disableLegacyMode,
disableDefaultPropsExceptForClasses,
enableSiblingPrerendering,
enableComponentPerformanceTrack,
enableYieldingBeforePassive,
enableThrottledScheduling,
@ -1061,7 +1060,7 @@ export function performWorkOnRoot(
// the main thread.
// TODO: We should consider doing this whenever a sync lane is suspended,
// even for regular pings.
(enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes));
checkIfRootIsPrerendering(root, lanes);
let exitStatus = shouldTimeSlice
? renderRootConcurrent(root, lanes)
@ -1072,11 +1071,7 @@ export function performWorkOnRoot(
do {
if (exitStatus === RootInProgress) {
// Render phase is still in progress.
if (
enableSiblingPrerendering &&
workInProgressRootIsPrerendering &&
!shouldTimeSlice
) {
if (workInProgressRootIsPrerendering && !shouldTimeSlice) {
// We're in prerendering mode, but time slicing is not enabled. This
// happens when something suspends during a synchronous update. Exit the
// the work loop. When we resume, we'll use the concurrent work loop so
@ -2057,27 +2052,13 @@ function handleThrow(root: FiberRoot, thrownValue: any): void {
// API for suspending. This implementation detail can change later, once we
// deprecate the old API in favor of `use`.
thrownValue = getSuspendedThenable();
workInProgressSuspendedReason =
// TODO: Suspending the work loop during the render phase is
// currently not compatible with sibling prerendering. We will add
// this optimization back in a later step.
!enableSiblingPrerendering &&
shouldRemainOnPreviousScreen() &&
// Check if there are other pending updates that might possibly unblock this
// component from suspending. This mirrors the check in
// renderDidSuspendDelayIfPossible. We should attempt to unify them somehow.
// TODO: Consider unwinding immediately, using the
// SuspendedOnHydration mechanism.
!includesNonIdleWork(workInProgressRootSkippedLanes) &&
!includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)
? // Suspend work loop until data resolves
thrownValue === SuspenseActionException
? SuspendedOnAction
: SuspendedOnData
: // Don't suspend work loop, except to check if the data has
// immediately resolved (i.e. in a microtask). Otherwise, trigger the
// nearest Suspense fallback.
SuspendedOnImmediate;
// TODO: Suspending the work loop during the render phase is
// currently not compatible with sibling prerendering. We will add
// this optimization back in a later step.
// Don't suspend work loop, except to check if the data has
// immediately resolved (i.e. in a microtask). Otherwise, trigger the
// nearest Suspense fallback.
workInProgressSuspendedReason = SuspendedOnImmediate;
} else if (thrownValue === SuspenseyCommitException) {
thrownValue = getSuspendedThenable();
workInProgressSuspendedReason = SuspendedOnInstance;
@ -2421,7 +2402,6 @@ function renderRootSync(
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason);
if (
enableSiblingPrerendering &&
shouldYieldForPrerendering &&
workInProgressRootIsPrerendering
) {
@ -3008,56 +2988,54 @@ function throwAndUnwindWorkLoop(
if (unitOfWork.flags & Incomplete) {
// Unwind the stack until we reach the nearest boundary.
let skipSiblings;
if (!enableSiblingPrerendering) {
skipSiblings = true;
} else {
if (
// The current algorithm for both hydration and error handling assumes
// that the tree is rendered sequentially. So we always skip the siblings.
getIsHydrating() ||
suspendedReason === SuspendedOnError
) {
skipSiblings = true;
// We intentionally don't set workInProgressRootDidSkipSuspendedSiblings,
// because we don't want to trigger another prerender attempt.
} else if (
// Check whether this is a prerender
!workInProgressRootIsPrerendering &&
// Offscreen rendering is also a form of speculative rendering
!includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
) {
// This is not a prerender. Skip the siblings during this render. A
// separate prerender will be scheduled for later.
skipSiblings = true;
workInProgressRootDidSkipSuspendedSiblings = true;
// Because we're skipping the siblings, schedule an immediate retry of
// this boundary.
//
// The reason we do this is because a prerender is only scheduled when
// the root is blocked from committing, i.e. RootSuspendedWithDelay.
// When the root is not blocked, as in the case when we render a
// fallback, the original lane is considered to be finished, and
// therefore no longer in need of being prerendered. However, there's
// still a pending retry that will happen once the data streams in.
// We should start rendering that even before the data streams in so we
// can prerender the siblings.
if (
suspendedReason === SuspendedOnData ||
suspendedReason === SuspendedOnAction ||
suspendedReason === SuspendedOnImmediate ||
suspendedReason === SuspendedOnDeprecatedThrowPromise
) {
const boundary = getSuspenseHandler();
if (boundary !== null && boundary.tag === SuspenseComponent) {
boundary.flags |= ScheduleRetry;
}
if (
// The current algorithm for both hydration and error handling assumes
// that the tree is rendered sequentially. So we always skip the siblings.
getIsHydrating() ||
suspendedReason === SuspendedOnError
) {
skipSiblings = true;
// We intentionally don't set workInProgressRootDidSkipSuspendedSiblings,
// because we don't want to trigger another prerender attempt.
} else if (
// Check whether this is a prerender
!workInProgressRootIsPrerendering &&
// Offscreen rendering is also a form of speculative rendering
!includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
) {
// This is not a prerender. Skip the siblings during this render. A
// separate prerender will be scheduled for later.
skipSiblings = true;
workInProgressRootDidSkipSuspendedSiblings = true;
// Because we're skipping the siblings, schedule an immediate retry of
// this boundary.
//
// The reason we do this is because a prerender is only scheduled when
// the root is blocked from committing, i.e. RootSuspendedWithDelay.
// When the root is not blocked, as in the case when we render a
// fallback, the original lane is considered to be finished, and
// therefore no longer in need of being prerendered. However, there's
// still a pending retry that will happen once the data streams in.
// We should start rendering that even before the data streams in so we
// can prerender the siblings.
if (
suspendedReason === SuspendedOnData ||
suspendedReason === SuspendedOnAction ||
suspendedReason === SuspendedOnImmediate ||
suspendedReason === SuspendedOnDeprecatedThrowPromise
) {
const boundary = getSuspenseHandler();
if (boundary !== null && boundary.tag === SuspenseComponent) {
boundary.flags |= ScheduleRetry;
}
} else {
// This is a prerender. Don't skip the siblings.
skipSiblings = false;
}
} else {
// This is a prerender. Don't skip the siblings.
skipSiblings = false;
}
unwindUnitOfWork(unitOfWork, skipSiblings);
} else {
// Although the fiber suspended, we're intentionally going to commit it in

View File

@ -205,9 +205,8 @@ describe('Activity Suspense', () => {
});
assertLog([
'Suspend! [hello]',
...(gate(flags => flags.enableSiblingPrerendering)
? ['Suspend! [hello]']
: []),
// pre-warming
'Suspend! [hello]',
]);
expect(root).toMatchRenderedOutput('Loading');

View File

@ -240,11 +240,10 @@ describe('Activity StrictMode', () => {
'Parent mount',
'Parent unmount',
'Parent mount',
...(gate('enableSiblingPrerendering')
? ['Child rendered', 'Child suspended']
: []),
// pre-warming
'Child rendered',
'Child suspended',
// end pre-warming
'------------------------------',
'Child rendered',
'Child rendered',

View File

@ -202,9 +202,8 @@ describe('Activity Suspense', () => {
});
assertLog([
'Suspend! [hello]',
...(gate(flags => flags.enableSiblingPrerendering)
? ['Suspend! [hello]']
: []),
// pre-warming
'Suspend! [hello]',
]);
expect(root).toMatchRenderedOutput('Loading');
@ -265,7 +264,8 @@ describe('Activity Suspense', () => {
assertLog([
'Open',
'Suspend! [Async]',
...(gate(flags => flags.enableSiblingPrerendering) ? ['Loading...'] : []),
// pre-warming
'Loading...',
]);
// It should suspend with delay to prevent the already-visible Suspense
// boundary from switching to a fallback
@ -276,7 +276,9 @@ describe('Activity Suspense', () => {
await resolveText('Async');
});
assertLog([
...(gate(flags => flags.enableSiblingPrerendering) ? ['Open'] : []),
// pre-warming
'Open',
// end pre-warming
'Async',
]);
expect(root).toMatchRenderedOutput(
@ -333,7 +335,8 @@ describe('Activity Suspense', () => {
assertLog([
'Open',
'Suspend! [Async]',
...(gate(flags => flags.enableSiblingPrerendering) ? ['Loading...'] : []),
// pre-warming
'Loading...',
]);
// It should suspend with delay to prevent the already-visible Suspense
// boundary from switching to a fallback

View File

@ -367,8 +367,8 @@ describe('act warnings', () => {
assertLog([
'Suspend! [Async]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Async]'] : []),
// pre-warming
'Suspend! [Async]',
]);
expect(root).toMatchRenderedOutput('Loading...');
@ -388,21 +388,19 @@ describe('act warnings', () => {
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
...(gate('enableSiblingPrerendering')
? [
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
]
: []),
// pre-warming
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
],
{withoutStack: true},

View File

@ -301,10 +301,9 @@ describe('ReactAsyncActions', () => {
'Async action ended',
'Pending: false',
'Suspend! [A1]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [B1]', 'Suspend! [C1]']
: []),
// pre-warming
'Suspend! [B1]',
'Suspend! [C1]',
]);
expect(root).toMatchRenderedOutput(
<>
@ -321,8 +320,8 @@ describe('ReactAsyncActions', () => {
'Pending: false',
'A1',
'Suspend! [B1]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C1]'] : []),
// pre-warming
'Suspend! [C1]',
]);
expect(root).toMatchRenderedOutput(
<>

View File

@ -113,8 +113,10 @@ describe('ReactBlockingMode', () => {
'A',
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [B]', 'C'] : []),
// pre-warming
'A',
'Suspend! [B]',
'C',
]);
// In Legacy Mode, A and B would mount in a hidden primary tree. In
// Concurrent Mode, nothing in the primary tree should mount. But the

View File

@ -233,8 +233,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// Inner contents suspended, so we continue showing a fallback.
assertLog([
'Suspend! [Inner]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Inner]'] : []),
// pre-warming
'Suspend! [Inner]',
]);
expect(root).toMatchRenderedOutput(
<>

View File

@ -399,10 +399,8 @@ describe('ReactConcurrentErrorRecovery', () => {
});
assertLog([
'Suspend! [Async]',
...(gate('enableSiblingPrerendering')
? ['Caught an error: Oops!']
: []),
// pre-warming
'Caught an error: Oops!',
]);
// The render suspended without committing the error.
expect(root).toMatchRenderedOutput(null);
@ -420,13 +418,7 @@ describe('ReactConcurrentErrorRecovery', () => {
);
});
});
assertLog([
'Suspend! [Async]',
...(gate('enableSiblingPrerendering')
? ['Caught an error: Oops!']
: []),
]);
assertLog(['Suspend! [Async]', 'Caught an error: Oops!']);
expect(root).toMatchRenderedOutput(null);
await act(async () => {

View File

@ -398,8 +398,8 @@ describe('ReactLazyContextPropagation', () => {
'Suspend! [B]',
'Loading...',
'B',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
expect(root).toMatchRenderedOutput('Loading...B');
@ -484,8 +484,8 @@ describe('ReactLazyContextPropagation', () => {
'Suspend! [B]',
'Loading...',
'B',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
expect(root).toMatchRenderedOutput('Loading...B');
@ -822,8 +822,8 @@ describe('ReactLazyContextPropagation', () => {
assertLog([
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
expect(root).toMatchRenderedOutput('Loading...');

View File

@ -420,10 +420,9 @@ describe('ReactDeferredValue', () => {
// The initial value suspended, so we attempt the final value, which
// also suspends.
'Suspend! [Final]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Loading...]', 'Suspend! [Final]']
: []),
// pre-warming
'Suspend! [Loading...]',
'Suspend! [Final]',
]);
expect(root).toMatchRenderedOutput(null);
@ -463,10 +462,9 @@ describe('ReactDeferredValue', () => {
// The initial value suspended, so we attempt the final value, which
// also suspends.
'Suspend! [Final]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Loading...]', 'Suspend! [Final]']
: []),
// pre-warming
'Suspend! [Loading...]',
'Suspend! [Final]',
]);
expect(root).toMatchRenderedOutput(null);
@ -507,8 +505,8 @@ describe('ReactDeferredValue', () => {
// The initial value suspended, so we attempt the final value, which
// also suspends.
'Suspend! [Final]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Final]'] : []),
// pre-warming
'Suspend! [Final]',
]);
expect(root).toMatchRenderedOutput('Fallback');
@ -541,10 +539,9 @@ describe('ReactDeferredValue', () => {
// The initial value suspended, so we attempt the final value, which
// also suspends.
'Suspend! [Final]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Loading...]', 'Suspend! [Final]']
: []),
// pre-warming
'Suspend! [Loading...]',
'Suspend! [Final]',
]);
expect(root).toMatchRenderedOutput(null);
@ -644,8 +641,8 @@ describe('ReactDeferredValue', () => {
// go straight to attempting the final value.
'Suspend! [Content]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Content]'] : []),
// pre-warming
'Suspend! [Content]',
]);
// The content suspended, so we show a Suspense fallback
expect(root).toMatchRenderedOutput('Loading...');

View File

@ -654,9 +654,10 @@ describe('ReactExpiration', () => {
});
await waitForAll([
'Suspend! [A1]',
...(gate('enableSiblingPrerendering') ? ['B', 'C'] : []),
// pre-warming
'B',
'C',
// end pre-warming
'Loading...',
]);

View File

@ -3658,8 +3658,8 @@ describe('ReactHooksWithNoopRenderer', () => {
'A',
'Suspend! [A]',
'Loading',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>

View File

@ -198,7 +198,10 @@ describe('ReactLazy', () => {
await resolveFakeImport(Foo);
await waitForAll(['Foo']);
await waitForAll([
'Foo',
...(gate('alwaysThrottleRetries') ? [] : ['Foo']),
]);
expect(root).not.toMatchRenderedOutput('FooBar');
await act(() => resolveFakeImport(Bar));
@ -326,8 +329,8 @@ describe('ReactLazy', () => {
await waitForAll([
'Suspend! [LazyChildA]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [LazyChildB]'] : []),
// pre-warming
'Suspend! [LazyChildB]',
]);
expect(root).not.toMatchRenderedOutput('AB');
@ -339,21 +342,12 @@ describe('ReactLazy', () => {
// we can unwrap the result synchronously if it already loaded. Like `use`.
await waitFor([
'A',
// When enableSiblingPrerendering is on, LazyChildB was already
// initialized. So it also already resolved when we called
// resolveFakeImport above. So it doesn't suspend again.
...(gate('enableSiblingPrerendering')
? ['B']
: ['Suspend! [LazyChildB]']),
// pre-warming: LazyChildB was already initialized. So it also already resolved
// when we called resolveFakeImport above. So it doesn't suspend again.
'B',
]);
});
assertLog([
...(gate('enableSiblingPrerendering') ? [] : ['A', 'B']),
'Did mount: A',
'Did mount: B',
]);
assertLog(['Did mount: A', 'Did mount: B']);
expect(root).toMatchRenderedOutput('AB');
// Swap the position of A and B
@ -1612,7 +1606,11 @@ describe('ReactLazy', () => {
expect(ref.current).toBe(null);
await act(() => resolveFakeImport(Foo));
assertLog(['Foo', ...(gate('enableSiblingPrerendering') ? ['Foo'] : [])]);
assertLog([
'Foo',
// pre-warming
'Foo',
]);
await act(() => resolveFakeImport(ForwardRefBar));
assertLog(['Foo', 'forwardRef', 'Bar']);
@ -1910,17 +1908,16 @@ describe('ReactLazy', () => {
await waitForAll([
'Init A',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Init B'] : []),
// pre-warming
'Init B',
]);
expect(root).not.toMatchRenderedOutput('AB');
await act(() => resolveFakeImport(ChildA));
assertLog([
'A',
// When enableSiblingPrerendering is on, B was already initialized.
...(gate('enableSiblingPrerendering') ? ['A'] : ['Init B']),
// pre-warming
'A',
]);
await act(() => resolveFakeImport(ChildB));

View File

@ -171,7 +171,7 @@ describe('ReactSiblingPrerendering', () => {
// After B suspends, we're still able to prerender C without starting
// over because there's no fallback, so the root is blocked from
// committing anyway.
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
'Suspend! [C]',
]);
});
@ -207,12 +207,10 @@ describe('ReactSiblingPrerendering', () => {
// The second render is a prerender of the hidden content.
await waitForPaint([
'Suspend! [B]',
// If B and C were visible, C would not have been attempted
// during this pass, because it would prevented the fallback
// from showing.
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
'Suspend! [C]',
'Loading...',
]);
expect(root).toMatchRenderedOutput('A');
@ -240,13 +238,11 @@ describe('ReactSiblingPrerendering', () => {
// Immediately after the fallback commits, retry the boundary again. This
// time we include B, since we're not blocking the fallback from showing.
if (gate('enableSiblingPrerendering')) {
if (gate(flags => flags.enableYieldingBeforePassive)) {
// Passive effects.
await waitForPaint([]);
}
await waitForPaint(['Suspend! [A]', 'Suspend! [B]']);
if (gate(flags => flags.enableYieldingBeforePassive)) {
// Passive effects.
await waitForPaint([]);
}
await waitForPaint(['Suspend! [A]', 'Suspend! [B]']);
});
expect(root).toMatchRenderedOutput('Loading...');
});
@ -282,11 +278,7 @@ describe('ReactSiblingPrerendering', () => {
// Now that the fallback is visible, we can prerender the siblings. Start
// prerendering, then yield to simulate an interleaved event.
if (gate('enableSiblingPrerendering')) {
await waitFor(['A']);
} else {
await waitForAll([]);
}
await waitFor(['A']);
// To avoid the Suspense throttling mechanism, let's pretend there's been
// more than a Just Noticeable Difference since we rendered the
@ -298,10 +290,6 @@ describe('ReactSiblingPrerendering', () => {
// shouldn't unwind and lose our work-in-progress.
await resolveText('B');
await waitForPaint([
// When sibling prerendering is not enabled, we weren't already rendering
// when the data for B came in, so A doesn't get rendered until now.
...(gate('enableSiblingPrerendering') ? [] : ['A']),
'B',
'Suspend! [C]',
@ -321,23 +309,19 @@ describe('ReactSiblingPrerendering', () => {
// Now that the inner fallback is showing, we can prerender the rest of
// the tree.
assertLog(
gate('enableSiblingPrerendering')
? [
// NOTE: C renders twice instead of once because when B resolved, it
// was treated like a retry update, not just a ping. So first it
// regular renders, then it prerenders. TODO: We should be able to
// optimize this by detecting inside the retry listener that the
// outer boundary is no longer suspended, and therefore doesn't need
// to be updated.
'Suspend! [C]',
assertLog([
// NOTE: C renders twice instead of once because when B resolved, it
// was treated like a retry update, not just a ping. So first it
// regular renders, then it prerenders. TODO: We should be able to
// optimize this by detecting inside the retry listener that the
// outer boundary is no longer suspended, and therefore doesn't need
// to be updated.
'Suspend! [C]',
// Now we're in prerender mode, so D is incuded in this attempt.
'Suspend! [C]',
'Suspend! [D]',
]
: [],
);
// Now we're in prerender mode, so D is incuded in this attempt.
'Suspend! [C]',
'Suspend! [D]',
]);
expect(root).toMatchRenderedOutput(
<div>
<div>AB</div>
@ -402,9 +386,7 @@ describe('ReactSiblingPrerendering', () => {
);
});
// Once the inner fallback is committed, we can start prerendering C.
assertLog(
gate('enableSiblingPrerendering') ? ['Suspend! [B]', 'Suspend! [C]'] : [],
);
assertLog(['Suspend! [B]', 'Suspend! [C]']);
});
it(
@ -488,9 +470,7 @@ describe('ReactSiblingPrerendering', () => {
await waitForPaint([]);
}
// Now we can proceed to prerendering C.
if (gate('enableSiblingPrerendering')) {
await waitForPaint(['Suspend! [B]', 'Suspend! [C]']);
}
await waitForPaint(['Suspend! [B]', 'Suspend! [C]']);
});
assertLog([]);
},
@ -519,12 +499,10 @@ describe('ReactSiblingPrerendering', () => {
// Synchronously render everything until we suspend in the shell
assertLog(['A', 'B', 'Suspend! [Async]']);
if (gate('enableSiblingPrerendering')) {
// The rest of the siblings begin to prerender concurrently. Notice
// that we don't unwind here; we pick up where we left off above.
await waitFor(['C']);
await waitFor(['D']);
}
// The rest of the siblings begin to prerender concurrently. Notice
// that we don't unwind here; we pick up where we left off above.
await waitFor(['C']);
await waitFor(['D']);
assertLog([]);
expect(root).toMatchRenderedOutput(null);
@ -555,10 +533,8 @@ describe('ReactSiblingPrerendering', () => {
// Synchronously render everything until we suspend in the shell
assertLog(['A', 'B', 'Suspend! [Async]']);
if (gate('enableSiblingPrerendering')) {
// The rest of the siblings begin to prerender concurrently
await waitFor(['C']);
}
// The rest of the siblings begin to prerender concurrently
await waitFor(['C']);
// While we're prerendering, Async resolves. We should unwind and
// start over, rather than continue prerendering D.

View File

@ -135,9 +135,9 @@ describe('ReactSuspense', () => {
'Bar',
// A suspends
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['B'] : []),
// pre-warming
'B',
// end pre-warming
'Loading...',
]);
expect(container.textContent).toEqual('');
@ -169,10 +169,9 @@ describe('ReactSuspense', () => {
'Loading A...',
'Suspend! [B]',
'Loading B...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
]);
expect(container.innerHTML).toEqual('Loading A...Loading B...');
@ -181,8 +180,7 @@ describe('ReactSuspense', () => {
await act(() => resolveText('A'));
assertLog([
'A',
...(gate('enableSiblingPrerendering')
...(gate('alwaysThrottleRetries')
? ['Suspend! [B]', 'Suspend! [B]']
: []),
]);
@ -288,10 +286,10 @@ describe('ReactSuspense', () => {
'Foo',
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Loading more...']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Loading more...',
]);
expect(container.textContent).toEqual('Loading...');
@ -341,10 +339,10 @@ describe('ReactSuspense', () => {
'Foo',
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Loading more...']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Loading more...',
]);
expect(container.textContent).toEqual('Loading...');
@ -390,10 +388,10 @@ describe('ReactSuspense', () => {
'Foo',
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Loading more...']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Loading more...',
]);
expect(container.textContent).toEqual('Loading...');
@ -482,8 +480,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [default]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [default]'] : []),
// pre-warming
'Suspend! [default]',
]);
await act(() => resolveText('default'));
@ -494,8 +492,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [new value]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [new value]'] : []),
// pre-warming
'Suspend! [new value]',
]);
await act(() => resolveText('new value'));
@ -539,8 +537,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [default]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [default]'] : []),
// pre-warming
'Suspend! [default]',
]);
await act(() => resolveText('default'));
@ -551,8 +549,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [new value]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [new value]'] : []),
// pre-warming
'Suspend! [new value]',
]);
await act(() => resolveText('new value'));
@ -593,8 +591,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [default]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [default]'] : []),
// pre-warming
'Suspend! [default]',
]);
await act(() => resolveText('default'));
@ -605,8 +603,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [new value]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [new value]'] : []),
// pre-warming
'Suspend! [new value]',
]);
await act(() => resolveText('new value'));
@ -647,8 +645,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [default]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [default]'] : []),
// pre-warming
'Suspend! [default]',
]);
await act(() => resolveText('default'));
@ -659,8 +657,8 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [new value]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [new value]'] : []),
// pre-warming
'Suspend! [new value]',
]);
await act(() => resolveText('new value'));
@ -708,10 +706,9 @@ describe('ReactSuspense', () => {
'Suspend! [Child 2]',
'Loading...',
'destroy layout',
...(gate('enableSiblingPrerendering')
? ['Child 1', 'Suspend! [Child 2]']
: []),
// pre-warming
'Child 1',
'Suspend! [Child 2]',
]);
await act(() => resolveText('Child 2'));
@ -737,13 +734,18 @@ describe('ReactSuspense', () => {
assertLog([
'Suspend! [Child 1]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Child 1]', 'Suspend! [Child 2]']
: []),
// pre-warming
'Suspend! [Child 1]',
'Suspend! [Child 2]',
]);
await resolveText('Child 1');
await waitForAll(['Child 1', 'Suspend! [Child 2]']);
await waitForAll([
'Child 1',
'Suspend! [Child 2]',
...(gate('alwaysThrottleRetries')
? []
: ['Child 1', 'Suspend! [Child 2]']),
]);
jest.advanceTimersByTime(6000);

View File

@ -60,9 +60,17 @@ describe('ReactSuspense', () => {
ReactNoop.render(elementBadType);
await waitForAll([]);
assertConsoleErrorDev(['Unexpected type for suspenseCallback.'], {
withoutStack: true,
});
assertConsoleErrorDev(
[
'Unexpected type for suspenseCallback.',
...(gate('alwaysThrottleRetries')
? []
: ['Unexpected type for suspenseCallback.']),
],
{
withoutStack: true,
},
);
const elementMissingCallback = (
<React.Suspense fallback={'Waiting'}>
@ -93,7 +101,10 @@ describe('ReactSuspense', () => {
ReactNoop.render(element);
await waitForAll([]);
expect(ReactNoop).toMatchRenderedOutput('Waiting');
expect(ops).toEqual([new Set([promise])]);
expect(ops).toEqual([
new Set([promise]),
...(gate('alwaysThrottleRetries') ? [] : new Set([promise])),
]);
ops = [];
await act(() => resolve());
@ -132,7 +143,10 @@ describe('ReactSuspense', () => {
ReactNoop.render(element);
await waitForAll([]);
expect(ReactNoop).toMatchRenderedOutput('Waiting Tier 1');
expect(ops).toEqual([new Set([promise1])]);
expect(ops).toEqual([
new Set([promise1]),
...(gate('alwaysThrottleRetries') ? [] : new Set([promise1, promise2])),
]);
ops = [];
await act(() => resolve1());
@ -141,8 +155,8 @@ describe('ReactSuspense', () => {
expect(ReactNoop).toMatchRenderedOutput('Waiting Tier 1');
expect(ops).toEqual([
new Set([promise2]),
...(gate('enableSiblingPrerendering') ? new Set([promise2]) : []),
// pre-warming
new Set([promise2]),
]);
ops = [];
@ -182,7 +196,10 @@ describe('ReactSuspense', () => {
await waitForAll([]);
expect(ReactNoop).toMatchRenderedOutput('Waiting Tier 2');
expect(ops1).toEqual([]);
expect(ops2).toEqual([new Set([promise])]);
expect(ops2).toEqual([
new Set([promise]),
...(gate('alwaysThrottleRetries') ? [] : [new Set([promise])]),
]);
});
// @gate enableSuspenseCallback
@ -231,11 +248,7 @@ describe('ReactSuspense', () => {
await act(() => resolve1());
expect(ReactNoop).toMatchRenderedOutput('Waiting Tier 2Done');
expect(ops1).toEqual([]);
expect(ops2).toEqual([
new Set([promise2]),
...(gate('enableSiblingPrerendering') ? new Set([promise2]) : []),
]);
expect(ops2).toEqual([new Set([promise2]), new Set([promise2])]);
ops1 = [];
ops2 = [];

View File

@ -283,14 +283,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create passive',
'Text:Outside create passive',
'App create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Inside:Before render',
'Suspend:Async',
'ClassText:Inside:After render',
]
: []),
// pre-warming
'Text:Inside:Before render',
'Suspend:Async',
'ClassText:Inside:After render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -687,14 +683,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
await waitForAll([
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Inside:Before render',
'Suspend:Async',
'Text:Inside:After render',
]
: []),
// pre-warming
'Text:Inside:Before render',
'Suspend:Async',
'Text:Inside:After render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -850,13 +842,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
</>,
);
});
if (gate('enableSiblingPrerendering')) {
assertLog([
'ClassText:Inside:Before render',
'Suspend:Async',
'ClassText:Inside:After render',
]);
}
// pre-warming
assertLog([
'ClassText:Inside:Before render',
'Suspend:Async',
'ClassText:Inside:After render',
]);
// Resolving the suspended resource should re-create inner layout effects.
await act(async () => {
@ -961,10 +952,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
await waitForAll([
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? ['Suspend:Async', 'Text:Outer render', 'Text:Inner render']
: []),
// pre-warming
'Suspend:Async',
'Text:Outer render',
'Text:Inner render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1088,10 +1079,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
await waitForAll([
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? ['Suspend:Async', 'Text:Outer render']
: []),
// pre-warming
'Suspend:Async',
'Text:Outer render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1195,10 +1185,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:InnerFallback create insertion',
'Text:InnerFallback create layout',
'Text:InnerFallback create passive',
...(gate('enableSiblingPrerendering')
? ['Text:Inner render', 'Suspend:InnerAsync_1']
: []),
// pre-warming
'Text:Inner render',
'Suspend:InnerAsync_1',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1228,16 +1217,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:OuterFallback create insertion',
'Text:OuterFallback create layout',
'Text:OuterFallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_1',
'Text:InnerFallback render',
]
: []),
// pre-warming
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_1',
'Text:InnerFallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1255,15 +1240,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
assertLog([
'Text:Outer render',
'Suspend:OuterAsync_1',
...(gate('enableSiblingPrerendering')
? [
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'AsyncText:InnerAsync_1 render',
]
: []),
// pre-warming
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'AsyncText:InnerAsync_1 render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1288,16 +1269,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:OuterFallback render',
...(gate('enableSiblingPrerendering')
? [
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_2',
'Text:InnerFallback render',
]
: []),
// pre-warming
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_2',
'Text:InnerFallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1325,10 +1302,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:InnerFallback create layout',
'Text:OuterFallback destroy passive',
'AsyncText:OuterAsync_1 create passive',
...(gate('enableSiblingPrerendering')
? ['Text:Inner render', 'Suspend:InnerAsync_2']
: []),
// pre-warming
'Text:Inner render',
'Suspend:InnerAsync_2',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1382,15 +1358,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:OuterFallback create insertion',
'Text:OuterFallback create layout',
'Text:OuterFallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Outer render',
'Suspend:OuterAsync_2',
'Text:Inner render',
'AsyncText:InnerAsync_2 render',
]
: []),
// pre-warming
'Text:Outer render',
'Suspend:OuterAsync_2',
'Text:Inner render',
'AsyncText:InnerAsync_2 render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1480,10 +1452,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:InnerFallback create insertion',
'Text:InnerFallback create layout',
'Text:InnerFallback create passive',
...(gate('enableSiblingPrerendering')
? ['Text:Inner render', 'Suspend:InnerAsync_1']
: []),
// pre-warming
'Text:Inner render',
'Suspend:InnerAsync_1',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1512,16 +1483,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:OuterFallback create insertion',
'Text:OuterFallback create layout',
'Text:OuterFallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_1',
'Text:InnerFallback render',
]
: []),
// pre-warming
'Text:Outer render',
'Suspend:OuterAsync_1',
'Text:Inner render',
'Suspend:InnerAsync_1',
'Text:InnerFallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1630,10 +1597,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
await waitForAll([
'Text:Fallback:Inside create passive',
'Text:Fallback:Outside create passive',
...(gate('enableSiblingPrerendering')
? ['Text:Inside render', 'Suspend:OutsideAsync']
: []),
// pre-warming
'Text:Inside render',
'Suspend:OutsideAsync',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1667,15 +1633,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
await waitForAll([
'Text:Fallback:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Inside render',
'Suspend:OutsideAsync',
'Text:Fallback:Inside render',
'Suspend:FallbackAsync',
]
: []),
// pre-warming
'Text:Inside render',
'Suspend:OutsideAsync',
'Text:Fallback:Inside render',
'Suspend:FallbackAsync',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1787,15 +1749,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback:Outside create layout',
'Text:Fallback:Fallback create passive',
'Text:Fallback:Outside create passive',
...(gate('enableSiblingPrerendering')
? [
'Text:Inside render',
'Suspend:OutsideAsync',
'Text:Fallback:Inside render',
'Suspend:FallbackAsync',
]
: []),
// pre-warming
'Text:Inside render',
'Suspend:OutsideAsync',
'Text:Fallback:Inside render',
'Suspend:FallbackAsync',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -1915,8 +1873,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
await waitForAll([
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering') ? ['Suspend:Suspend'] : []),
// pre-warming
'Suspend:Suspend',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2038,10 +1996,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? ['Suspend:Async', 'ThrowsInDidMount render', 'Text:Inside render']
: []),
// pre-warming
'Suspend:Async',
'ThrowsInDidMount render',
'Text:Inside render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2301,14 +2259,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Suspend:Async',
'ThrowsInLayoutEffect render',
'Text:Inside render',
]
: []),
// pre-warming
'Suspend:Async',
'ThrowsInLayoutEffect render',
'Text:Inside render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2555,14 +2509,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
);
});
if (gate('enableSiblingPrerendering')) {
assertLog([
'Text:Function render',
'Suspend:Async_1',
'Suspend:Async_2',
'ClassText:Class render',
]);
}
// pre-warming
assertLog([
'Text:Function render',
'Suspend:Async_1',
'Suspend:Async_2',
'ClassText:Class render',
]);
// Resolving the suspended resource should re-create inner layout effects.
await act(async () => {
@ -2572,15 +2525,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Function render',
'AsyncText:Async_1 render',
'Suspend:Async_2',
...(gate('enableSiblingPrerendering')
? [
'Text:Function render',
'AsyncText:Async_1 render',
'Suspend:Async_2',
'ClassText:Class render',
]
: []),
// pre-warming
'Text:Function render',
'AsyncText:Async_1 render',
'Suspend:Async_2',
'ClassText:Class render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2715,14 +2664,14 @@ describe('ReactSuspenseEffectsSemantics', () => {
</>,
);
});
if (gate('enableSiblingPrerendering')) {
assertLog([
'Text:Function render',
'Suspender "A" render',
'Suspend:A',
'ClassText:Class render',
]);
}
// pre-warming
assertLog([
'Text:Function render',
'Suspender "A" render',
'Suspend:A',
'ClassText:Class render',
]);
// Resolving the suspended resource should re-create inner layout effects.
textToRead = 'B';
@ -2733,15 +2682,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Function render',
'Suspender "B" render',
'Suspend:B',
...(gate('enableSiblingPrerendering')
? [
'Text:Function render',
'Suspender "B" render',
'Suspend:B',
'ClassText:Class render',
]
: []),
// pre-warming
'Text:Function render',
'Suspender "B" render',
'Suspend:B',
'ClassText:Class render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2977,15 +2922,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Suspend:Async',
'RefCheckerOuter render',
'RefCheckerInner:refObject render',
'RefCheckerInner:refCallback render',
]
: []),
// pre-warming
'Suspend:Async',
'RefCheckerOuter render',
'RefCheckerInner:refObject render',
'RefCheckerInner:refCallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -3089,17 +3030,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Suspend:Async',
'RefCheckerOuter render',
'ClassComponent:refObject render',
'RefCheckerInner:refObject render',
'ClassComponent:refCallback render',
'RefCheckerInner:refCallback render',
]
: []),
// pre-warming
'Suspend:Async',
'RefCheckerOuter render',
'ClassComponent:refObject render',
'RefCheckerInner:refObject render',
'ClassComponent:refCallback render',
'RefCheckerInner:refCallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Fallback" />);
@ -3199,17 +3136,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Suspend:Async',
'RefCheckerOuter render',
'FunctionComponent render',
'RefCheckerInner:refObject render',
'FunctionComponent render',
'RefCheckerInner:refCallback render',
]
: []),
// pre-warming
'Suspend:Async',
'RefCheckerOuter render',
'FunctionComponent render',
'RefCheckerInner:refObject render',
'FunctionComponent render',
'RefCheckerInner:refCallback render',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Fallback" />);
@ -3311,10 +3244,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? ['Suspend:Async', 'RefChecker render']
: []),
// pre-warming
'Suspend:Async',
'RefChecker render',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Fallback" />);
@ -3433,14 +3365,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
'Text:Fallback create insertion',
'Text:Fallback create layout',
'Text:Fallback create passive',
...(gate('enableSiblingPrerendering')
? [
'Suspend:Async',
'ThrowsInRefCallback render',
'Text:Inside render',
]
: []),
// pre-warming
'Suspend:Async',
'ThrowsInRefCallback render',
'Text:Inside render',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>

View File

@ -142,8 +142,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
});
@ -159,8 +159,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
// null
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
});
@ -176,8 +176,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
// null
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
});
@ -195,8 +195,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
});
@ -214,8 +214,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
// null
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
});
@ -233,8 +233,8 @@ describe('ReactSuspenseFallback', () => {
await waitForAll([
'Suspend! [A]',
// null
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
});

View File

@ -245,9 +245,9 @@ describe('ReactSuspenseList', () => {
'Loading B',
'Suspend! [C]',
'Loading C',
...(gate('enableSiblingPrerendering')
? ['Suspend! [B]', 'Suspend! [C]']
: []),
// pre-warming
'Suspend! [B]',
'Suspend! [C]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -260,7 +260,7 @@ describe('ReactSuspenseList', () => {
await act(() => C.resolve());
assertLog(
gate('enableSiblingPrerendering')
gate('alwaysThrottleRetries')
? ['Suspend! [B]', 'C', 'Suspend! [B]']
: ['C'],
);
@ -746,7 +746,8 @@ describe('ReactSuspenseList', () => {
await waitForAll([
'Suspend! [A]',
'Loading',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span>Loading</span>);
@ -919,8 +920,8 @@ describe('ReactSuspenseList', () => {
'Loading A',
'Loading B',
'Loading C',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -932,12 +933,7 @@ describe('ReactSuspenseList', () => {
);
await act(() => A.resolve());
assertLog([
'A',
'Suspend! [B]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
]);
assertLog(['A', 'Suspend! [B]', 'Suspend! [B]']);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -990,8 +986,8 @@ describe('ReactSuspenseList', () => {
'Loading C',
'Loading B',
'Loading A',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
// pre-warming
'Suspend! [C]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -1006,8 +1002,8 @@ describe('ReactSuspenseList', () => {
assertLog([
'C',
'Suspend! [B]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -1133,8 +1129,8 @@ describe('ReactSuspenseList', () => {
'A',
'C',
'Suspend! [E]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [E]'] : []),
// pre-warming
'Suspend! [E]',
]);
// We can now resolve the full head.
@ -1153,8 +1149,8 @@ describe('ReactSuspenseList', () => {
assertLog([
'E',
'Suspend! [F]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [F]'] : []),
// pre-warming
'Suspend! [F]',
]);
// In the tail we can resolve one-by-one.
@ -1296,10 +1292,9 @@ describe('ReactSuspenseList', () => {
'E',
'Suspend! [F]',
'Loading F',
...(gate('enableSiblingPrerendering')
? ['Suspend! [D]', 'Suspend! [F]']
: []),
// pre-warming
'Suspend! [D]',
'Suspend! [F]',
]);
// This will suspend, since the boundaries are avoided. Give them
@ -1347,8 +1342,8 @@ describe('ReactSuspenseList', () => {
'D',
'F',
'Suspend! [B]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
// We can now resolve the full head.
@ -1369,8 +1364,8 @@ describe('ReactSuspenseList', () => {
assertLog([
'B',
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// In the tail we can resolve one-by-one.
@ -1493,8 +1488,8 @@ describe('ReactSuspenseList', () => {
await waitForAll([
'Suspend! [A]',
'Loading A',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span>Loading A</span>);
@ -2007,8 +2002,8 @@ describe('ReactSuspenseList', () => {
'Suspend! [D]',
'Loading D',
'Loading E',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
// This is suspended due to the update to D causing a loading state.
@ -2030,7 +2025,11 @@ describe('ReactSuspenseList', () => {
await B.resolve();
await waitForAll(['B', 'Suspend! [C]']);
await waitForAll([
'B',
'Suspend! [C]',
...(!gate('alwaysThrottleRetries') ? ['Suspend! [C]'] : []),
]);
// Incremental loading is suspended.
jest.advanceTimersByTime(500);
@ -2425,8 +2424,8 @@ describe('ReactSuspenseList', () => {
'A',
'Suspend! [B]',
'Loading B',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -2511,8 +2510,8 @@ describe('ReactSuspenseList', () => {
await waitForAll([
'Suspend! [A]',
'Loading A',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span>Loading A</span>);
});
@ -2795,8 +2794,8 @@ describe('ReactSuspenseList', () => {
'B',
'Suspend! [C]',
'Fallback',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
// pre-warming
'Suspend! [C]',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2805,7 +2804,9 @@ describe('ReactSuspenseList', () => {
<span>Loading...</span>
</>,
);
expect(onRender).toHaveBeenCalledTimes(1);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 1 : 2,
);
// The treeBaseDuration should be the time to render each child. The last
// one counts the fallback time.
@ -2828,12 +2829,18 @@ describe('ReactSuspenseList', () => {
<span>C</span>
</>,
);
expect(onRender).toHaveBeenCalledTimes(2);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 2 : 3,
);
// actualDuration
expect(onRender.mock.calls[1][2]).toBe(1 + 4 + 5);
expect(onRender.mock.calls[1][2]).toBe(
gate('alwaysThrottleRetries') ? 1 + 4 + 5 : 5,
);
// treeBaseDuration
expect(onRender.mock.calls[1][3]).toBe(1 + 4 + 5);
expect(onRender.mock.calls[1][3]).toBe(
gate('alwaysThrottleRetries') ? 1 + 4 + 5 : 8,
);
ReactNoop.render(<App addRow={true} suspendTail={true} />);
@ -2850,8 +2857,8 @@ describe('ReactSuspenseList', () => {
'Fallback',
// Lastly we render the tail.
'Fallback',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
// pre-warming
'Suspend! [C]',
]);
// Flush suspended time.
@ -2867,7 +2874,7 @@ describe('ReactSuspenseList', () => {
</>,
);
expect(onRender).toHaveBeenCalledTimes(
gate('enableSiblingPrerendering') ? 4 : 3,
gate('alwaysThrottleRetries') ? 4 : 5,
);
// The treeBaseDuration should be the time to render the first two
@ -2877,16 +2884,20 @@ describe('ReactSuspenseList', () => {
// with force fallback mode.
// actualDuration
expect(onRender.mock.calls[2][2]).toBe((1 + 4 + 5 + 3) * 2 + 3);
expect(onRender.mock.calls[2][2]).toBe(
gate('alwaysThrottleRetries') ? (1 + 4 + 5 + 3) * 2 + 3 : 10,
);
// treeBaseDuration
expect(onRender.mock.calls[2][3]).toBe(1 + 4 + 3 + 3);
expect(onRender.mock.calls[2][3]).toBe(
gate('alwaysThrottleRetries') ? 1 + 4 + 3 + 3 : 10,
);
await act(() => C.resolve());
assertLog([
'C',
'Suspend! [D]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [D]'] : []),
// pre-warming
'Suspend! [D]',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2897,21 +2908,16 @@ describe('ReactSuspenseList', () => {
</>,
);
if (gate('enableSiblingPrerendering')) {
expect(onRender).toHaveBeenCalledTimes(6);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 6 : 7,
);
// actualDuration
expect(onRender.mock.calls[5][2]).toBe(12);
// treeBaseDuration
expect(onRender.mock.calls[5][3]).toBe(1 + 4 + 5 + 3);
} else {
expect(onRender).toHaveBeenCalledTimes(4);
// actualDuration
expect(onRender.mock.calls[3][2]).toBe(5 + 12);
// treeBaseDuration
expect(onRender.mock.calls[3][3]).toBe(1 + 4 + 5 + 3);
}
// actualDuration
expect(onRender.mock.calls[5][2]).toBe(
gate('alwaysThrottleRetries') ? 12 : 17,
);
// treeBaseDuration
expect(onRender.mock.calls[5][3]).toBe(1 + 4 + 5 + 3);
});
// @gate enableSuspenseList
@ -2977,8 +2983,8 @@ describe('ReactSuspenseList', () => {
'Loading A',
'Loading B',
'Loading C',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(
@ -2990,12 +2996,7 @@ describe('ReactSuspenseList', () => {
);
await act(() => A.resolve());
assertLog([
'A',
'Suspend! [B]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
]);
assertLog(['A', 'Suspend! [B]', 'Suspend! [B]']);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span>A</span>

View File

@ -139,8 +139,10 @@ describe('ReactSuspensePlaceholder', () => {
'A',
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [B]', 'C'] : []),
// pre-warming
'A',
'Suspend! [B]',
'C',
]);
expect(ReactNoop).toMatchRenderedOutput('Loading...');
@ -160,8 +162,9 @@ describe('ReactSuspensePlaceholder', () => {
await waitForAll([
'Suspend! [B2]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B2]', 'C'] : []),
// pre-warming
'Suspend! [B2]',
'C',
]);
// Time out the update
@ -209,8 +212,10 @@ describe('ReactSuspensePlaceholder', () => {
'A',
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [B]', 'C'] : []),
// pre-warming
'A',
'Suspend! [B]',
'C',
]);
expect(ReactNoop).not.toMatchRenderedOutput('ABC');
@ -225,8 +230,10 @@ describe('ReactSuspensePlaceholder', () => {
'A',
'Suspend! [B2]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [B2]', 'C'] : []),
// pre-warming
'A',
'Suspend! [B2]',
'C',
]);
// Time out the update
jest.advanceTimersByTime(750);
@ -264,8 +271,10 @@ describe('ReactSuspensePlaceholder', () => {
'a',
'Suspend! [b]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['a', 'Suspend! [b]', 'c'] : []),
// pre-warming
'a',
'Suspend! [b]',
'c',
]);
expect(ReactNoop).toMatchRenderedOutput(<uppercase>LOADING...</uppercase>);
@ -280,8 +289,9 @@ describe('ReactSuspensePlaceholder', () => {
'a',
'Suspend! [b2]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['a', 'Suspend! [b2]', 'c'] : []),
'a',
'Suspend! [b2]',
'c',
]);
// Time out the update
jest.advanceTimersByTime(750);
@ -375,15 +385,17 @@ describe('ReactSuspensePlaceholder', () => {
'Suspending',
'Suspend! [Loaded]',
'Fallback',
...(gate('enableSiblingPrerendering')
? ['Suspending', 'Suspend! [Loaded]', 'Text']
: []),
// pre-warming
'Suspending',
'Suspend! [Loaded]',
'Text',
]);
// Since this is initial render we immediately commit the fallback. Another test below
// deals with the update case where this suspends.
expect(ReactNoop).toMatchRenderedOutput('Loading...');
expect(onRender).toHaveBeenCalledTimes(1);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 1 : 2,
);
// Initial mount only shows the "Loading..." Fallback.
// The treeBaseDuration then should be 10ms spent rendering Fallback,
@ -401,21 +413,12 @@ describe('ReactSuspensePlaceholder', () => {
]);
expect(ReactNoop).toMatchRenderedOutput('LoadedText');
if (gate('enableSiblingPrerendering')) {
expect(onRender).toHaveBeenCalledTimes(3);
expect(onRender).toHaveBeenCalledTimes(3);
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 8ms re-rendering Suspending and AsyncText.
expect(onRender.mock.calls[2][2]).toBe(8);
expect(onRender.mock.calls[2][3]).toBe(8);
} else {
expect(onRender).toHaveBeenCalledTimes(2);
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 8ms re-rendering Suspending and AsyncText.
expect(onRender.mock.calls[1][2]).toBe(8);
expect(onRender.mock.calls[1][3]).toBe(8);
}
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 8ms re-rendering Suspending and AsyncText.
expect(onRender.mock.calls[2][2]).toBe(8);
expect(onRender.mock.calls[2][3]).toBe(8);
});
});
@ -536,14 +539,16 @@ describe('ReactSuspensePlaceholder', () => {
'Suspending',
'Suspend! [Loaded]',
'Fallback',
...(gate('enableSiblingPrerendering')
? ['Suspending', 'Suspend! [Loaded]', 'Text']
: []),
// pre-warming
'Suspending',
'Suspend! [Loaded]',
'Text',
]);
// Show the fallback UI.
expect(ReactNoop).toMatchRenderedOutput('Loading...');
expect(onRender).toHaveBeenCalledTimes(2);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 2 : 3,
);
jest.advanceTimersByTime(900);
@ -579,15 +584,16 @@ describe('ReactSuspensePlaceholder', () => {
'Suspend! [Loaded]',
'Fallback',
'Suspend! [Sibling]',
...(gate('enableSiblingPrerendering')
? ['Suspending', 'Suspend! [Loaded]', 'New', 'Suspend! [Sibling]']
: []),
// pre-warming
'Suspending',
'Suspend! [Loaded]',
'New',
'Suspend! [Sibling]',
]);
expect(ReactNoop).toMatchRenderedOutput('Loading...');
expect(onRender).toHaveBeenCalledTimes(
gate('enableSiblingPrerendering') ? 4 : 3,
gate('alwaysThrottleRetries') ? 4 : 5,
);
// Resolve the pending promise.
@ -600,23 +606,17 @@ describe('ReactSuspensePlaceholder', () => {
await waitForAll(['Suspending', 'Loaded', 'New', 'Sibling']);
});
if (gate('enableSiblingPrerendering')) {
expect(onRender).toHaveBeenCalledTimes(5);
expect(onRender).toHaveBeenCalledTimes(
gate('alwaysThrottleRetries') ? 5 : 6,
);
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 6ms rendering Text,
// the 2ms rendering Suspending, and the 1ms rendering AsyncText.
expect(onRender.mock.calls[4][2]).toBe(9);
expect(onRender.mock.calls[4][3]).toBe(9);
} else {
expect(onRender).toHaveBeenCalledTimes(4);
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 6ms rendering Text,
// the 2ms rendering Suspending, and the 1ms rendering AsyncText.
expect(onRender.mock.calls[3][2]).toBe(9);
expect(onRender.mock.calls[3][3]).toBe(9);
}
// When the suspending data is resolved and our final UI is rendered,
// both times should include the 6ms rendering Text,
// the 2ms rendering Suspending, and the 1ms rendering AsyncText.
expect(onRender.mock.calls[4][2]).toBe(9);
expect(onRender.mock.calls[4][3]).toBe(
gate('alwaysThrottleRetries') ? 9 : 10,
);
});
});
});

View File

@ -296,7 +296,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// A suspends
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['B'] : []),
// pre-warming
'B',
// end pre-warming
// We immediately unwind and switch to a fallback without
// rendering siblings.
@ -334,10 +336,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Loading A...',
'Suspend! [B]',
'Loading B...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -351,8 +352,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await act(() => resolveText('A'));
assertLog([
'A',
...(gate('enableSiblingPrerendering')
...(gate('alwaysThrottleRetries')
? ['Suspend! [B]', 'Suspend! [B]']
: []),
]);
@ -395,9 +395,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'A',
'Suspend! [B]',
...(gate('enableSiblingPrerendering') ? ['C', 'D'] : []),
// pre-warming
'C',
'D',
// end pre-warming
'Loading...',
]);
// Did not commit yet.
@ -509,8 +510,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [Result]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Result]'] : []),
// pre-warming
'Suspend! [Result]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
@ -562,8 +563,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'A',
'Suspend! [1]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [1]'] : []),
// pre-warming
'Suspend! [1]',
]);
await act(() => resolveText('1'));
@ -631,9 +632,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
});
await waitForAll([
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['B'] : []),
// pre-warming
'B',
// end pre-warming
'Loading...',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
@ -765,14 +766,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// The async content suspends
'Suspend! [Outer content]',
'Loading outer...',
...(gate('enableSiblingPrerendering')
? [
'Suspend! [Outer content]',
'Suspend! [Inner content]',
'Loading inner...',
]
: []),
// pre-warming
'Suspend! [Outer content]',
'Suspend! [Inner content]',
'Loading inner...',
]);
// The outer loading state finishes immediately.
expect(ReactNoop).toMatchRenderedOutput(
@ -952,10 +949,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
@ -1068,10 +1064,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
ReactNoop.render(<App />);
await waitForAll([
'Suspend! [A]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Suspend! [C]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Suspend! [C]',
]);
expect(ReactNoop).toMatchRenderedOutput('Loading...');
@ -1735,10 +1731,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// A suspends
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Loading more...']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Loading more...',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
@ -1753,8 +1749,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// B suspends
'Suspend! [B]',
'Loading more...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
// Because we've already been waiting for so long we've exceeded
@ -1799,10 +1795,10 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// A suspends
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]', 'Loading more...']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
'Loading more...',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
@ -1881,10 +1877,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Loading A...',
'Suspend! [B]',
'Loading B...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
@ -2035,8 +2030,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput('Loading...');
@ -2046,10 +2041,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [A]',
...(gate('enableSiblingPrerendering')
? ['Suspend! [A]', 'Suspend! [B]']
: []),
// pre-warming
'Suspend! [A]',
'Suspend! [B]',
]);
});
@ -2108,8 +2102,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
await resolveText('A');
@ -2138,8 +2132,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [A]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
await resolveText('A');
@ -2168,8 +2162,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Foo',
'Suspend! [A]',
'Initial load...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]', 'B'] : []),
// pre-warming
'Suspend! [A]',
'B',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Initial load..." />);
@ -2191,8 +2186,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Suspend! [C]',
'Updating...',
'B',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [C]'] : []),
// pre-warming
'A',
'Suspend! [C]',
]);
// Flush to skip suspended time.
Scheduler.unstable_advanceTime(600);
@ -2240,8 +2236,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Suspend! [A]',
'B',
// null
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="B" />);
@ -2263,8 +2259,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Suspend! [C]',
// null
'B',
...(gate('enableSiblingPrerendering') ? ['A', 'Suspend! [C]'] : []),
// pre-warming
'A',
'Suspend! [C]',
]);
// Flush to skip suspended time.
Scheduler.unstable_advanceTime(600);
@ -2312,8 +2309,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'A',
'Suspend! [B]',
'Loading B...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
// Flush to skip suspended time.
Scheduler.unstable_advanceTime(600);
@ -2394,8 +2391,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'A',
'Suspend! [B]',
// Null
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
// Still suspended.
expect(ReactNoop).toMatchRenderedOutput(<span prop="A" />);
@ -2424,8 +2421,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2478,8 +2475,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2538,8 +2535,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2587,8 +2584,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2652,8 +2649,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2727,8 +2724,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [A]'] : []),
// pre-warming
'Suspend! [A]',
]);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
@ -2794,8 +2791,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Hi!',
'Suspend! [A]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Hi!', 'Suspend! [A]'] : []),
// pre-warming
'Hi!',
'Suspend! [A]',
]);
await act(() => resolveText('A'));
assertLog(['Hi!', 'A']);
@ -3117,73 +3115,6 @@ describe('ReactSuspenseWithNoopRenderer', () => {
},
);
// TODO: This test is substantially different when sibling prerendering is
// enabled because we never work on Idle updates if there are pending retries.
// This was already an issue before the enableSiblingPrerendering change but
// it's exacerbated by the fact that we schedule a retry immediately. I'm not
// going to bother to update this test for now, though, because Idle updates
// aren't actually used and should probably just be deleted unless/until we
// finish the feature. Feel free to delete if needed.
// @gate !enableSiblingPrerendering
// @gate enableLegacyCache
it(
'multiple updates originating inside a Suspense boundary at different ' +
'priority levels are not dropped, including Idle updates',
async () => {
const {useState} = React;
const root = ReactNoop.createRoot();
function Parent() {
return (
<>
<Suspense fallback={<Text text="Loading..." />}>
<Child />
</Suspense>
</>
);
}
let setText;
function Child() {
const [text, _setText] = useState('A');
setText = _setText;
return <AsyncText text={text} />;
}
await seedNextTextCache('A');
await act(() => {
root.render(<Parent />);
});
assertLog(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
await act(async () => {
// Schedule two updates that originate inside the Suspense boundary.
// The first one causes the boundary to suspend. The second one is at
// lower priority and unsuspends it by hiding the async component.
setText('B');
await resolveText('C');
ReactNoop.idleUpdates(() => {
setText('C');
});
// First we attempt the high pri update. It suspends.
await waitForPaint(['Suspend! [B]', 'Loading...']);
expect(root).toMatchRenderedOutput(
<>
<span hidden={true} prop="A" />
<span prop="Loading..." />
</>,
);
// Now flush the remaining work. The Idle update successfully finishes.
await waitForAll(['C']);
expect(root).toMatchRenderedOutput(<span prop="C" />);
});
},
);
// @gate enableLegacyCache
it(
'fallback component can update itself even after a high pri update to ' +
@ -3226,8 +3157,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await waitForAll([
'Suspend! [B]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []),
// pre-warming
'Suspend! [B]',
]);
});
@ -3264,8 +3195,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// Then complete the update to the fallback.
'Still loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
'Suspend! [C]',
]);
expect(root).toMatchRenderedOutput(
<>
@ -3326,12 +3256,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
await act(() => {
setText('C');
});
assertLog([
'Suspend! [C]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
]);
assertLog(['Suspend! [C]', 'Loading...', 'Suspend! [C]']);
// Commit. This will insert a fragment fiber to wrap around the component
// that triggered the update.
@ -3411,8 +3336,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [C]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [C]'] : []),
// pre-warming
'Suspend! [C]',
]);
// Commit. This will insert a fragment fiber to wrap around the component
@ -3444,9 +3369,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
// be able to finish rendering.
assertLog([
'Suspend! [D]',
...(gate('enableSiblingPrerendering') ? ['Suspend! [D]'] : []),
// pre-warming
'Suspend! [D]',
// end pre-warming
'E',
]);
expect(root).toMatchRenderedOutput(<span prop="E" />);
@ -3534,10 +3459,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Outer step: 0',
'Suspend! [Inner text: B]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Inner text: B]', 'Inner step: 0']
: []),
// pre-warming
'Suspend! [Inner text: B]',
'Inner step: 0',
]);
// Commit the placeholder
await advanceTimers(250);
@ -3566,10 +3490,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Outer step: 1',
'Suspend! [Inner text: B]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Inner text: B]', 'Inner step: 1']
: []),
// pre-warming
'Suspend! [Inner text: B]',
'Inner step: 1',
]);
expect(root).toMatchRenderedOutput(
<>
@ -3664,8 +3587,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'Outer: B0',
'Suspend! [Inner: B0]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Inner: B0]'] : []),
// pre-warming
'Suspend! [Inner: B0]',
]);
// Commit the placeholder
await advanceTimers(250);
@ -3907,77 +3830,6 @@ describe('ReactSuspenseWithNoopRenderer', () => {
});
});
// TODO: This test is substantially different when sibling prerendering is
// enabled because we never work on Idle updates if there are pending retries.
// This was already an issue before the enableSiblingPrerendering change but
// it's exacerbated by the fact that we schedule a retry immediately. I'm not
// going to bother to update this test for now, though, because Idle updates
// aren't actually used and should probably just be deleted unless/until we
// finish the feature. Feel free to delete if needed.
// @gate !enableSiblingPrerendering
// @gate enableLegacyCache
it('regression related to Idle updates (outdated experiment): #18657', async () => {
const {useState} = React;
let setText;
function App() {
const [text, _setText] = useState('A');
setText = _setText;
return <AsyncText text={text} />;
}
const root = ReactNoop.createRoot();
await act(async () => {
await seedNextTextCache('A');
root.render(
<Suspense fallback={<Text text="Loading..." />}>
<App />
</Suspense>,
);
});
assertLog(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
await act(async () => {
setText('B');
ReactNoop.idleUpdates(() => {
setText('C');
});
// Suspend the first update. This triggers an immediate fallback because
// it wasn't wrapped in startTransition.
await waitForPaint(['Suspend! [B]', 'Loading...']);
expect(root).toMatchRenderedOutput(
<>
<span hidden={true} prop="A" />
<span prop="Loading..." />
</>,
);
// Once the fallback renders, proceed to the Idle update. This will
// also suspend.
await waitForAll(['Suspend! [C]']);
});
// Finish loading B.
await act(async () => {
setText('B');
await resolveText('B');
});
// We did not try to render the Idle update again because there have been no
// additional updates since the last time it was attempted.
assertLog(['B']);
expect(root).toMatchRenderedOutput(<span prop="B" />);
// Finish loading C.
await act(async () => {
setText('C');
await resolveText('C');
});
assertLog(['C']);
expect(root).toMatchRenderedOutput(<span prop="C" />);
});
// @gate enableLegacyCache
it('retries have lower priority than normal updates', async () => {
const {useState} = React;
@ -4004,8 +3856,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'A',
'Suspend! [Async]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Async]'] : []),
// pre-warming
'Suspend! [Async]',
]);
expect(root).toMatchRenderedOutput(
<>
@ -4076,8 +3928,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
assertLog([
'Suspend! [Async]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend! [Async]'] : []),
// pre-warming
'Suspend! [Async]',
]);
expect(root).toMatchRenderedOutput(
<>
@ -4248,10 +4100,11 @@ describe('ReactSuspenseWithNoopRenderer', () => {
'1',
'Suspend! [Async]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend! [Async]', 'A', 'B', 'C']
: []),
// pre-warming
'Suspend! [Async]',
'A',
'B',
'C',
]);
expect(root).toMatchRenderedOutput(
<>

View File

@ -860,9 +860,9 @@ describe('ReactTransition', () => {
assertLog([
// Suspend.
'Suspend! [Async]',
...(gate('enableSiblingPrerendering') ? ['Normal pri: 0'] : []),
// pre-warming
'Normal pri: 0',
// end pre-warming
'Loading...',
]);
expect(root).toMatchRenderedOutput('(empty), Normal pri: 0');

View File

@ -442,7 +442,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(page transition, 1000)',
'onTransitionProgress(page transition, 1000, 2000, [suspense page])',
]);
@ -533,7 +535,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(page transition, 1000)',
'onTransitionProgress(page transition, 1000, 1000, [suspense page])',
]);
@ -552,7 +556,9 @@ describe('ReactInteractionTracing', () => {
'Suspend [Show Text]',
'Show Text Loading...',
'Page Two',
...(gate('enableSiblingPrerendering') ? ['Suspend [Show Text]'] : []),
// pre-warming
'Suspend [Show Text]',
// end pre-warming
'onTransitionStart(text transition, 2000)',
'onTransitionProgress(text transition, 2000, 2000, [show text])',
]);
@ -642,7 +648,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(page transition, 1000)',
'onTransitionProgress(page transition, 1000, 2000, [suspense page])',
]);
@ -656,9 +664,10 @@ describe('ReactInteractionTracing', () => {
'Show Text Loading...',
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Show Text]', 'Suspend [Page Two]']
: []),
// pre-warming
'Suspend [Show Text]',
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(show text, 2000)',
'onTransitionProgress(show text, 2000, 2000, [show text])',
]);
@ -761,15 +770,13 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Page Two]',
'Suspend [Show Text One]',
'Show Text One Loading...',
'Suspend [Show Text Two]',
'Show Text Two Loading...',
]
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Show Text One]',
'Show Text One Loading...',
'Suspend [Show Text Two]',
'Show Text Two Loading...',
// end pre-warming
'onTransitionStart(page transition, 1000)',
'onTransitionProgress(page transition, 1000, 2000, [suspense page])',
]);
@ -784,9 +791,10 @@ describe('ReactInteractionTracing', () => {
'Show Text One Loading...',
'Suspend [Show Text Two]',
'Show Text Two Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Show Text One]', 'Suspend [Show Text Two]']
: []),
// pre-warming
'Suspend [Show Text One]',
'Suspend [Show Text Two]',
// end pre-warming
'onTransitionProgress(page transition, 1000, 3000, [show text one, show text two])',
]);
@ -899,15 +907,13 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Page Two]',
'Suspend [Show Text One]',
'Show Text One Loading...',
'Suspend [Show Text]',
'Show Text Loading...',
]
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Show Text One]',
'Show Text One Loading...',
'Suspend [Show Text]',
'Show Text Loading...',
// end pre-warming
'onTransitionStart(navigate, 1000)',
'onTransitionStart(show text one, 1000)',
'onTransitionProgress(navigate, 1000, 2000, [suspense page])',
@ -923,9 +929,10 @@ describe('ReactInteractionTracing', () => {
'Show Text One Loading...',
'Suspend [Show Text]',
'Show Text Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Show Text One]', 'Suspend [Show Text]']
: []),
// pre-warming
'Suspend [Show Text One]',
'Suspend [Show Text]',
// end pre-warming
'onTransitionProgress(navigate, 1000, 3000, [show text one, <null>])',
'onTransitionProgress(show text one, 1000, 3000, [show text one, <null>])',
]);
@ -942,13 +949,11 @@ describe('ReactInteractionTracing', () => {
'Show Text Loading...',
'Suspend [Show Text Two]',
'Show Text Two Loading...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Show Text One]',
'Suspend [Show Text]',
'Suspend [Show Text Two]',
]
: []),
// pre-warming
'Suspend [Show Text One]',
'Suspend [Show Text]',
'Suspend [Show Text Two]',
// end pre-warming
'onTransitionStart(show text two, 3000)',
'onTransitionProgress(show text two, 3000, 4000, [show text two])',
]);
@ -1153,9 +1158,11 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Page Two]', 'Suspend [Marker Text]', 'Loading...']
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Marker Text]',
'Loading...',
// end pre-warming
'onTransitionStart(page transition, 1000)',
]);
@ -1167,7 +1174,9 @@ describe('ReactInteractionTracing', () => {
'Page Two',
'Suspend [Marker Text]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Marker Text]'] : []),
// pre-warming
'Suspend [Marker Text]',
// end pre-warming
'onMarkerProgress(page transition, async marker, 1000, 3000, [marker suspense])',
'onMarkerComplete(page transition, sync marker, 1000, 3000)',
]);
@ -1271,15 +1280,13 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Outer Text]',
'Outer...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Outer Text]',
'Suspend [Inner Text One]',
'Inner One...',
'Suspend [Inner Text Two]',
'Inner Two...',
]
: []),
// pre-warming
'Suspend [Outer Text]',
'Suspend [Inner Text One]',
'Inner One...',
'Suspend [Inner Text Two]',
'Inner Two...',
// end pre-warming
'onTransitionStart(page transition, 1000)',
'onMarkerProgress(page transition, outer marker, 1000, 2000, [outer])',
]);
@ -1297,9 +1304,9 @@ describe('ReactInteractionTracing', () => {
'Suspend [Inner Text One]',
'Inner One...',
'Inner Text Two',
...(gate('enableSiblingPrerendering')
? ['Suspend [Inner Text One]']
: []),
// pre-warming
'Suspend [Inner Text One]',
// end pre-warming
'onMarkerProgress(page transition, outer marker, 1000, 4000, [inner one])',
'onMarkerComplete(page transition, marker two, 1000, 4000)',
]);
@ -1535,9 +1542,10 @@ describe('ReactInteractionTracing', () => {
'Loading...',
'Suspend [Sibling Text]',
'Sibling Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Page Two]', 'Suspend [Sibling Text]']
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Sibling Text]',
// end pre-warming
'onTransitionStart(transition one, 1000)',
'onMarkerProgress(transition one, parent, 1000, 2000, [suspense page, suspense sibling])',
'onMarkerProgress(transition one, marker one, 1000, 2000, [suspense page])',
@ -1553,9 +1561,10 @@ describe('ReactInteractionTracing', () => {
'Loading...',
'Suspend [Sibling Text]',
'Sibling Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Page Two]', 'Suspend [Sibling Text]']
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Sibling Text]',
// end pre-warming
'onMarkerProgress(transition one, parent, 1000, 3000, [suspense sibling])',
'onMarkerIncomplete(transition one, marker one, 1000, [{endTime: 3000, name: marker one, type: marker}, {endTime: 3000, name: suspense page, type: suspense}])',
'onMarkerIncomplete(transition one, parent, 1000, [{endTime: 3000, name: marker one, type: marker}, {endTime: 3000, name: suspense page, type: suspense}])',
@ -1569,9 +1578,9 @@ describe('ReactInteractionTracing', () => {
'Loading...',
'Suspend [Sibling Text]',
'Sibling Loading...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Page Two]', 'Suspend [Sibling Text]']
: []),
// pre-warming
'Suspend [Page Two]',
'Suspend [Sibling Text]',
]);
});
@ -1693,9 +1702,10 @@ describe('ReactInteractionTracing', () => {
'Loading One...',
'Suspend [Page Two]',
'Loading Two...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Page One]', 'Suspend [Page Two]']
: []),
// pre-warming
'Suspend [Page One]',
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(transition, 1000)',
'onMarkerProgress(transition, parent, 1000, 2000, [suspense one, suspense two])',
'onMarkerProgress(transition, one, 1000, 2000, [suspense one])',
@ -1709,7 +1719,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading Two...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
'onMarkerProgress(transition, parent, 1000, 3000, [suspense two])',
'onMarkerIncomplete(transition, one, 1000, [{endTime: 3000, name: one, type: marker}, {endTime: 3000, name: suspense one, type: suspense}])',
'onMarkerIncomplete(transition, parent, 1000, [{endTime: 3000, name: one, type: marker}, {endTime: 3000, name: suspense one, type: suspense}])',
@ -1836,14 +1848,12 @@ describe('ReactInteractionTracing', () => {
'Loading One...',
'Suspend [Page Two]',
'Loading Two...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Page One]',
'Suspend [Child]',
'Loading Child...',
'Suspend [Page Two]',
]
: []),
// pre-warming
'Suspend [Page One]',
'Suspend [Child]',
'Loading Child...',
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(transition, 1000)',
'onMarkerProgress(transition, parent, 1000, 2000, [suspense one, suspense two])',
'onMarkerProgress(transition, one, 1000, 2000, [suspense one])',
@ -1858,7 +1868,9 @@ describe('ReactInteractionTracing', () => {
'Page One',
'Suspend [Child]',
'Loading Child...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Child]'] : []),
// pre-warming
'Suspend [Child]',
// end pre-warming
'onMarkerProgress(transition, parent, 1000, 3000, [suspense two, suspense child])',
'onMarkerProgress(transition, one, 1000, 3000, [suspense child])',
'onMarkerComplete(transition, page one, 1000, 3000)',
@ -1871,7 +1883,10 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Page Two]',
'Loading Two...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
// "suspense one" has unsuspended so shouldn't be included
// tracing marker "page one" has completed so shouldn't be included
// all children of "suspense child" haven't yet been rendered so shouldn't be included
@ -1969,7 +1984,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Child]',
...(gate('enableSiblingPrerendering') ? ['Suspend [Child]'] : []),
// pre-warming
'Suspend [Child]',
// end pre-warming
'onTransitionStart(transition, 0)',
'onMarkerProgress(transition, parent, 0, 1000, [child])',
'onTransitionProgress(transition, 0, 1000, [child])',
@ -1983,9 +2000,9 @@ describe('ReactInteractionTracing', () => {
await waitForAll([
'Suspend [Appended child]',
'Suspend [Child]',
...(gate('enableSiblingPrerendering')
? ['Suspend [Appended child]', 'Suspend [Child]']
: []),
// pre-warming
'Suspend [Appended child]',
'Suspend [Child]',
]);
// This deleted child isn't part of the transition so we
@ -1995,7 +2012,8 @@ describe('ReactInteractionTracing', () => {
await advanceTimers(1000);
await waitForAll([
'Suspend [Child]',
...(gate('enableSiblingPrerendering') ? ['Suspend [Child]'] : []),
// pre-warming
'Suspend [Child]',
]);
await resolveText('Child');
@ -2097,7 +2115,9 @@ describe('ReactInteractionTracing', () => {
assertLog([
'Suspend [Child]',
...(gate('enableSiblingPrerendering') ? ['Suspend [Child]'] : []),
// pre-warming
'Suspend [Child]',
// end pre-warming
'onTransitionStart(transition one, 0)',
'onMarkerProgress(transition one, parent, 0, 1000, [child])',
'onTransitionProgress(transition one, 0, 1000, [child])',
@ -2118,9 +2138,10 @@ describe('ReactInteractionTracing', () => {
assertLog([
'Suspend [Appended child]',
'Suspend [Child]',
...(gate('enableSiblingPrerendering')
? ['Suspend [Appended child]', 'Suspend [Child]']
: []),
// pre-warming
'Suspend [Appended child]',
'Suspend [Child]',
// end pre-warming
'onTransitionStart(transition two, 1000)',
'onMarkerProgress(transition two, appended child, 1000, 2000, [appended child])',
'onTransitionProgress(transition two, 1000, 2000, [appended child])',
@ -2134,7 +2155,9 @@ describe('ReactInteractionTracing', () => {
assertLog([
'Suspend [Child]',
...(gate('enableSiblingPrerendering') ? ['Suspend [Child]'] : []),
// pre-warming
'Suspend [Child]',
// end pre-warming
'onMarkerProgress(transition two, appended child, 1000, 3000, [])',
'onMarkerIncomplete(transition two, appended child, 1000, [{endTime: 3000, name: appended child, type: suspense}])',
]);
@ -2291,20 +2314,11 @@ describe('ReactInteractionTracing', () => {
assertLog([
'Suspend [Text]',
'Loading...',
...(gate('enableSiblingPrerendering')
? [
'Suspend [Text]',
'onTransitionStart(transition, 0)',
'Suspend [Hidden Text]',
'Hidden Loading...',
]
: [
'Suspend [Hidden Text]',
'Hidden Loading...',
'onTransitionStart(transition, 0)',
]),
// pre-warming
'Suspend [Text]',
'onTransitionStart(transition, 0)',
'Suspend [Hidden Text]',
'Hidden Loading...',
]);
await act(() => {
@ -2368,7 +2382,9 @@ describe('ReactInteractionTracing', () => {
assertLog([
'Suspend [Page Two]',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Page Two]'] : []),
// pre-warming
'Suspend [Page Two]',
// end pre-warming
'onTransitionStart(page transition, 0)',
'onTransitionProgress(page transition, 0, 1000, [suspense page])',
]);
@ -2440,10 +2456,13 @@ describe('ReactInteractionTracing', () => {
'Text',
'Suspend [Text Two]',
'Loading Two...',
...(gate('enableSiblingPrerendering') ? ['Suspend [Text Two]'] : []),
// pre-warming
'Suspend [Text Two]',
// end pre-warming
'onTransitionStart(transition, 0)',
'onTransitionProgress(transition, 0, 1000, [two])',
...(gate('enableSiblingPrerendering') ? ['Suspend [Text Two]'] : []),
// pre-warming
'Suspend [Text Two]',
]);
await act(() => {
@ -2515,9 +2534,10 @@ describe('ReactInteractionTracing', () => {
'Loading one...',
'Suspend [Text two]',
'Loading two...',
...(gate('enableSiblingPrerendering')
? ['Suspend [Text one]', 'Suspend [Text two]']
: []),
// pre-warming
'Suspend [Text one]',
'Suspend [Text two]',
// end pre-warming
'onTransitionStart(transition one, 0) /root one/',
'onTransitionProgress(transition one, 0, 1000, [one]) /root one/',
'onTransitionStart(transition two, 0) /root two/',

View File

@ -196,8 +196,8 @@ describe('ReactUse', () => {
assertLog([
'Suspend!',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['Suspend!'] : []),
// pre-warming
'Suspend!',
]);
expect(root).toMatchRenderedOutput('Loading...');
});
@ -1123,10 +1123,9 @@ describe('ReactUse', () => {
});
assertLog([
'(Loading A...)',
...(gate('enableSiblingPrerendering')
? ['(Loading C...)', '(Loading B...)']
: []),
// pre-warming
'(Loading C...)',
'(Loading B...)',
]);
expect(root).toMatchRenderedOutput('(Loading A...)');
@ -2051,16 +2050,12 @@ describe('ReactUse', () => {
assertLog(['Async text requested [World]']);
await act(() => resolveTextRequests('World'));
assertConsoleErrorDev(
gate('enableSiblingPrerendering')
? [
'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' +
' in App (at **)',
]
: [],
);
assertConsoleErrorDev([
'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' +
' in App (at **)',
]);
assertLog(['Hi', 'World']);
expect(root).toMatchRenderedOutput('Hi World');
@ -2107,17 +2102,13 @@ describe('ReactUse', () => {
assertLog(['Async text requested [World]']);
await act(() => resolveTextRequests('World'));
assertConsoleErrorDev(
gate('enableSiblingPrerendering')
? [
'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' +
' in div (at **)\n' +
' in App (at **)',
]
: [],
);
assertConsoleErrorDev([
'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' +
' in div (at **)\n' +
' in App (at **)',
]);
assertLog(['Hi', 'World']);
expect(root).toMatchRenderedOutput(<div>Hi World</div>);

View File

@ -907,10 +907,9 @@ describe('StrictEffectsMode', () => {
'Child suspended',
'Fallback',
'Fallback',
...(gate('enableSiblingPrerendering')
? ['Child rendered', 'Child suspended']
: []),
// pre-warming
'Child rendered',
'Child suspended',
]);
log = [];
@ -932,10 +931,9 @@ describe('StrictEffectsMode', () => {
'Fallback',
'Parent dep destroy',
'Parent dep create',
...(gate('enableSiblingPrerendering')
? ['Child rendered', 'Child suspended']
: []),
// pre-warming
'Child rendered',
'Child suspended',
]);
log = [];

View File

@ -333,8 +333,8 @@ describe('useSyncExternalStore', () => {
// This should a synchronous re-render of A using the updated value. In
// this test, this causes A to suspend.
'Suspend A',
...(gate('enableSiblingPrerendering') ? ['B: Updated'] : []),
// pre-warming
'B: Updated',
]);
// Nothing has committed, because A suspended and no fallback
// was provided.
@ -419,7 +419,9 @@ describe('useSyncExternalStore', () => {
await act(async () => {
root.render(<App />);
});
assertLog([...(gate('enableSiblingPrerendering') ? ['(not set)'] : [])]);
// pre-warming
assertLog(['(not set)']);
expect(root).toMatchRenderedOutput('Loading...');
@ -429,11 +431,12 @@ describe('useSyncExternalStore', () => {
resolveText('A');
});
assertLog([
...(gate('enableSiblingPrerendering')
? ['A', 'B', 'A', 'B', 'B']
: gate(flags => flags.alwaysThrottleRetries)
? ['A', '(not set)', 'A', '(not set)', 'B']
: ['A', '(not set)', 'A', '(not set)', '(not set)', 'B']),
'A',
'B',
'A',
'B',
'B',
...(gate('alwaysThrottleRetries') ? [] : ['B']),
]);
expect(root).toMatchRenderedOutput('AB');

View File

@ -141,8 +141,6 @@ export const enablePersistedModeClonedFlag = false;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;
/**
* Enables an expiration time for retry lanes to avoid starvation.
*/

View File

@ -23,7 +23,6 @@ export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
export const enablePersistedModeClonedFlag = __VARIANT__;
export const enableShallowPropDiffing = __VARIANT__;
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
export const enableSiblingPrerendering = __VARIANT__;
export const enableFastAddPropertiesInDiffing = __VARIANT__;
export const enableLazyPublicInstanceInFabric = __VARIANT__;
export const renameElementSymbol = __VARIANT__;

View File

@ -25,7 +25,6 @@ export const {
enablePersistedModeClonedFlag,
enableShallowPropDiffing,
passChildrenWhenCloningPersistedNodes,
enableSiblingPrerendering,
enableFastAddPropertiesInDiffing,
enableLazyPublicInstanceInFabric,
renameElementSymbol,

View File

@ -61,8 +61,6 @@ export const renameElementSymbol = true;
export const retryLaneExpirationMs = 5000;
export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
export const enableSiblingPrerendering = true;
export const enableHydrationLaneScheduling = true;
export const enableYieldingBeforePassive = false;

View File

@ -62,7 +62,6 @@ export const enableInfiniteRenderLoopDetection = false;
export const renameElementSymbol = true;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;
export const enableYieldingBeforePassive = true;

View File

@ -60,7 +60,6 @@ export const renameElementSymbol = false;
export const retryLaneExpirationMs = 5000;
export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
export const enableSiblingPrerendering = true;
export const enableHydrationLaneScheduling = true;
export const enableYieldingBeforePassive = false;
export const enableThrottledScheduling = false;

View File

@ -71,7 +71,6 @@ export const renameElementSymbol = false;
export const enableObjectFiber = false;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;
export const enableHydrationLaneScheduling = true;

View File

@ -33,7 +33,6 @@ export const transitionLaneExpirationMs = 5000;
export const enableSchedulingProfiler = __VARIANT__;
export const enableInfiniteRenderLoopDetection = __VARIANT__;
export const enableSiblingPrerendering = __VARIANT__;
export const enableFastAddPropertiesInDiffing = __VARIANT__;
export const enableLazyPublicInstanceInFabric = false;

View File

@ -26,7 +26,6 @@ export const {
enableObjectFiber,
enableRenderableContext,
enableRetryLaneExpiration,
enableSiblingPrerendering,
enableTransitionTracing,
enableTrustedTypesIntegration,
favorSafetyOverHydrationPerf,

View File

@ -87,7 +87,7 @@ function getTestFlags() {
// TODO: Suspending the work loop during the render phase is currently
// not compatible with sibling prerendering. We will add this optimization
// back in a later step.
enableSuspendingDuringWorkLoop: !featureFlags.enableSiblingPrerendering,
enableSuspendingDuringWorkLoop: false,
// This flag is used to determine whether we should run Fizz tests using
// the external runtime or the inline script runtime.