diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js
index 073c5053ada78..3d08f3ae33e24 100644
--- a/packages/react/src/__tests__/ReactProfiler-test.internal.js
+++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js
@@ -2198,9 +2198,9 @@ describe('Profiler', () => {
return text;
} catch (promise) {
if (typeof promise.then === 'function') {
- yieldForRenderer(`Suspend! [${text}]`);
+ yieldForRenderer(`Suspend [${text}]`);
} else {
- yieldForRenderer(`Error! [${text}]`);
+ yieldForRenderer(`Error [${text}]`);
}
throw promise;
}
@@ -2242,7 +2242,7 @@ describe('Profiler', () => {
expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0);
expect(ReactNoop.flush()).toEqual([
- 'Suspend! [Async]',
+ 'Suspend [Async]',
'Text [Loading...]',
'Text [Sync]',
]);
@@ -2422,7 +2422,7 @@ describe('Profiler', () => {
advanceTimeBy(1500);
await awaitableAdvanceTimers(1500);
- expect(renderer).toFlushAll(['Suspend! [loaded]', 'Text [loading]']);
+ expect(renderer).toFlushAll(['Suspend [loaded]', 'Text [loading]']);
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
advanceTimeBy(2500);
@@ -2473,6 +2473,192 @@ describe('Profiler', () => {
onInteractionScheduledWorkCompleted,
).toHaveBeenLastNotifiedOfInteraction(interaction);
});
+
+ it('handles high-pri renderers between suspended and resolved (sync) trees', async () => {
+ const initialRenderInteraction = {
+ id: 0,
+ name: 'initial render',
+ timestamp: mockNow(),
+ };
+
+ const onRender = jest.fn();
+ let renderer;
+ SchedulerTracing.unstable_trace(
+ initialRenderInteraction.name,
+ initialRenderInteraction.timestamp,
+ () => {
+ renderer = ReactTestRenderer.create(
+
+ }>
+
+
+
+ ,
+ );
+ },
+ );
+ expect(renderer.toJSON()).toEqual(['loading', 'initial']);
+
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(2); // Sync null commit, placeholder commit
+ expect(onRender.mock.calls[0][6]).toMatchInteractions([
+ initialRenderInteraction,
+ ]);
+ onRender.mockClear();
+
+ const highPriUpdateInteraction = {
+ id: 1,
+ name: 'hiPriUpdate',
+ timestamp: mockNow(),
+ };
+
+ const originalPromise = resourcePromise;
+
+ renderer.unstable_flushSync(() => {
+ SchedulerTracing.unstable_trace(
+ highPriUpdateInteraction.name,
+ highPriUpdateInteraction.timestamp,
+ () => {
+ renderer.update(
+
+ }>
+
+
+
+ ,
+ );
+ },
+ );
+ });
+ expect(renderer.toJSON()).toEqual(['loading', 'updated']);
+
+ expect(onRender).toHaveBeenCalledTimes(2); // Sync null commit, placeholder commit
+ expect(onRender.mock.calls[0][6]).toMatchInteractions([
+ initialRenderInteraction,
+ highPriUpdateInteraction,
+ ]);
+ onRender.mockClear();
+
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+
+ advanceTimeBy(1000);
+ jest.advanceTimersByTime(1000);
+ await originalPromise;
+ expect(renderer.toJSON()).toEqual(['loaded', 'updated']);
+
+ expect(onRender).toHaveBeenCalledTimes(2);
+ expect(onRender.mock.calls[0][6]).toMatchInteractions([
+ initialRenderInteraction,
+ highPriUpdateInteraction,
+ ]);
+
+ expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
+ expect(
+ onInteractionScheduledWorkCompleted.mock.calls[0][0],
+ ).toMatchInteraction(initialRenderInteraction);
+ expect(
+ onInteractionScheduledWorkCompleted.mock.calls[1][0],
+ ).toMatchInteraction(highPriUpdateInteraction);
+ });
+
+ it('handles high-pri renderers between suspended and resolved (async) trees', async () => {
+ const initialRenderInteraction = {
+ id: 0,
+ name: 'initial render',
+ timestamp: mockNow(),
+ };
+
+ const onRender = jest.fn();
+ let renderer;
+ SchedulerTracing.unstable_trace(
+ initialRenderInteraction.name,
+ initialRenderInteraction.timestamp,
+ () => {
+ renderer = ReactTestRenderer.create(
+
+ }>
+
+
+
+ ,
+ {unstable_isAsync: true},
+ );
+ },
+ );
+ expect(renderer).toFlushAll([
+ 'Suspend [loaded]',
+ 'Text [loading]',
+ 'Text [initial]',
+ ]);
+
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).not.toHaveBeenCalled();
+
+ advanceTimeBy(500);
+ jest.advanceTimersByTime(500);
+
+ const highPriUpdateInteraction = {
+ id: 1,
+ name: 'hiPriUpdate',
+ timestamp: mockNow(),
+ };
+
+ const originalPromise = resourcePromise;
+
+ renderer.unstable_flushSync(() => {
+ SchedulerTracing.unstable_trace(
+ highPriUpdateInteraction.name,
+ highPriUpdateInteraction.timestamp,
+ () => {
+ renderer.update(
+
+ }>
+
+
+
+ ,
+ );
+ },
+ );
+ });
+ expect(renderer.toJSON()).toEqual(['loading', 'updated']);
+
+ expect(onRender).toHaveBeenCalledTimes(1);
+ expect(onRender.mock.calls[0][6]).toMatchInteractions([
+ highPriUpdateInteraction,
+ ]);
+ onRender.mockClear();
+
+ expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
+ expect(
+ onInteractionScheduledWorkCompleted,
+ ).toHaveBeenLastNotifiedOfInteraction(highPriUpdateInteraction);
+
+ advanceTimeBy(500);
+ jest.advanceTimersByTime(500);
+ await originalPromise;
+ expect(renderer).toFlushAll(['AsyncText [loaded]']);
+ expect(renderer.toJSON()).toEqual(['loaded', 'updated']);
+
+ expect(onRender).toHaveBeenCalledTimes(1);
+ expect(onRender.mock.calls[0][6]).toMatchInteractions([
+ initialRenderInteraction,
+ highPriUpdateInteraction,
+ ]);
+
+ expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
+ expect(
+ onInteractionScheduledWorkCompleted,
+ ).toHaveBeenLastNotifiedOfInteraction(initialRenderInteraction);
+ });
});
});
});