Skip to content

Commit 6a7a89d

Browse files
author
Brian Vaughn
committed
Added failing tests for two remaining suspense cases
1 parent 24f4070 commit 6a7a89d

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

packages/react/src/__tests__/ReactProfiler-test.internal.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,7 @@ describe('Profiler', () => {
12401240

12411241
loadModules({
12421242
enableSchedulerTracking: true,
1243+
enableSuspense: true,
12431244
});
12441245

12451246
throwInOnInteractionScheduledWorkCompleted = false;
@@ -2301,5 +2302,159 @@ describe('Profiler', () => {
23012302
onInteractionScheduledWorkCompleted,
23022303
).toHaveBeenLastNotifiedOfInteraction(interaction);
23032304
});
2305+
2306+
it('does not prematurely complete for suspended sync renders', async () => {
2307+
const SimpleCacheProvider = require('simple-cache-provider');
2308+
let cache;
2309+
function invalidateCache() {
2310+
cache = SimpleCacheProvider.createCache(invalidateCache);
2311+
}
2312+
invalidateCache();
2313+
2314+
let resourcePromise;
2315+
const TextResource = SimpleCacheProvider.createResource(
2316+
([text, ms = 0]) => {
2317+
resourcePromise = new Promise((resolve, reject) =>
2318+
setTimeout(() => resolve(text), ms),
2319+
);
2320+
return resourcePromise;
2321+
},
2322+
([text, ms]) => text,
2323+
);
2324+
2325+
function AsyncText({ms, text}) {
2326+
TextResource.read(cache, [text, ms]);
2327+
return <span prop={text} />;
2328+
}
2329+
2330+
function Text({text}) {
2331+
return text;
2332+
}
2333+
2334+
const interaction = {
2335+
id: 0,
2336+
name: 'initial render',
2337+
timestamp: mockNow(),
2338+
};
2339+
2340+
const onRender = jest.fn();
2341+
let renderer;
2342+
SchedulerTracking.unstable_track(
2343+
interaction.name,
2344+
interaction.timestamp,
2345+
() => {
2346+
renderer = ReactTestRenderer.create(
2347+
<React.unstable_Profiler id="app" onRender={onRender}>
2348+
<React.Placeholder
2349+
delayMs={1000}
2350+
fallback={<Text text="loading" />}>
2351+
<AsyncText text="loaded" ms={2000} />
2352+
</React.Placeholder>
2353+
</React.unstable_Profiler>,
2354+
);
2355+
},
2356+
);
2357+
2358+
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
2359+
2360+
jest.runAllTimers();
2361+
await resourcePromise;
2362+
2363+
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
2364+
expect(
2365+
onInteractionScheduledWorkCompleted,
2366+
).toHaveBeenLastNotifiedOfInteraction(interaction);
2367+
});
2368+
2369+
it('does not prematurely complete for suspended renders that have exceeded their deadline', async () => {
2370+
function awaitableAdvanceTimers(ms) {
2371+
jest.advanceTimersByTime(ms);
2372+
// Wait until the end of the current tick
2373+
return new Promise(resolve => {
2374+
setImmediate(resolve);
2375+
});
2376+
}
2377+
2378+
const SimpleCacheProvider = require('simple-cache-provider');
2379+
let cache;
2380+
function invalidateCache() {
2381+
cache = SimpleCacheProvider.createCache(invalidateCache);
2382+
}
2383+
invalidateCache();
2384+
2385+
const TextResource = SimpleCacheProvider.createResource(
2386+
([text, ms = 0]) => {
2387+
return new Promise((resolve, reject) => {
2388+
setTimeout(() => {
2389+
ReactTestRenderer.unstable_yield(`Promise resolved [${text}]`);
2390+
resolve(text);
2391+
}, ms);
2392+
});
2393+
},
2394+
([text, ms]) => text,
2395+
);
2396+
2397+
function AsyncText({ms, text}) {
2398+
try {
2399+
TextResource.read(cache, [text, ms]);
2400+
ReactTestRenderer.unstable_yield(`AsyncText [${text}]`);
2401+
return <span prop={text} />;
2402+
} catch (promise) {
2403+
if (typeof promise.then === 'function') {
2404+
ReactTestRenderer.unstable_yield(`Suspend! [${text}]`);
2405+
} else {
2406+
ReactTestRenderer.unstable_yield(`Error! [${text}]`);
2407+
}
2408+
throw promise;
2409+
}
2410+
}
2411+
2412+
function Text({text}) {
2413+
ReactTestRenderer.unstable_yield(`Text [${text}]`);
2414+
return text;
2415+
}
2416+
2417+
const interaction = {
2418+
id: 0,
2419+
name: 'initial render',
2420+
timestamp: mockNow(),
2421+
};
2422+
2423+
const onRender = jest.fn();
2424+
let renderer;
2425+
SchedulerTracking.unstable_track(
2426+
interaction.name,
2427+
interaction.timestamp,
2428+
() => {
2429+
renderer = ReactTestRenderer.create(
2430+
<React.unstable_Profiler id="app" onRender={onRender}>
2431+
<React.Placeholder
2432+
delayMs={1000}
2433+
fallback={<Text text="loading" />}>
2434+
<AsyncText text="loaded" ms={2000} />
2435+
</React.Placeholder>
2436+
</React.unstable_Profiler>,
2437+
{
2438+
unstable_isAsync: true,
2439+
},
2440+
);
2441+
},
2442+
);
2443+
2444+
advanceTimeBy(1500);
2445+
await awaitableAdvanceTimers(1500);
2446+
2447+
expect(renderer).toFlushAll(['Suspend! [loaded]', 'Text [loading]']);
2448+
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
2449+
2450+
advanceTimeBy(2500);
2451+
await awaitableAdvanceTimers(2500);
2452+
2453+
expect(renderer).toFlushAll(['AsyncText [loaded]']);
2454+
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
2455+
expect(
2456+
onInteractionScheduledWorkCompleted,
2457+
).toHaveBeenLastNotifiedOfInteraction(interaction);
2458+
});
23042459
});
23052460
});

0 commit comments

Comments
 (0)