Files
HealthLog/e2e/utils/deferred-sections.ts
T
Marc-André Bombeck 4916a29bbe perf(insights): mount below-the-fold overview sections near the viewport
Entering the Insights overview fired every section's reads at once, about
two dozen requests on a seeded account, and the server worked through
them in a queue: the hero and the first sections waited behind trends,
the period review, cycle, signals, rhythm events, health status,
breathing, labs and ECG, all far below the fold.

The first three sections in the account's own order still mount with
the page. Every later one renders a 1 px sentinel until it comes within
400 px of the visible area of the shell's scroll container, then mounts
and fetches; once mounted it stays. Measured on a seeded account under a
4x CPU slowdown: 24 -> 13 requests on entry, the entry network span
1.3-1.8 s -> 0.5-0.9 s, LCP about 1.35 s -> 0.9 s, blocking time about
550 ms -> 200 ms. Scrolling to the end still loads all 25 and renders
all ten sections.

Specs that assert on, measure or scan the lower sections scroll them in
first through a shared helper, so their coverage is unchanged.
2026-10-04 16:24:37 +02:00

39 lines
1.4 KiB
TypeScript

import { expect, type Page } from "@playwright/test";
/**
* Mount every overview section that waits for the viewport.
*
* Sections below the first screens of `/insights` render as a 1 px
* `[data-deferred-section]` sentinel until they come near the visible area
* (`src/components/insights/defer-until-near.tsx`). A spec that asserts on
* one of them, or measures or scans the whole page, scrolls each sentinel
* into view first, the way a reader would, until none is left. Polled, since
* the observers only exist once the page has hydrated.
*/
export async function revealDeferredSections(page: Page): Promise<void> {
// The sentinels render with the overview itself; until the hero is there,
// "no sentinel" only means the page has not rendered yet.
await expect(page.locator('[data-slot="insights-hero-strip"]')).toBeAttached({
timeout: 20_000,
});
const sentinels = page.locator("[data-deferred-section]");
await expect
.poll(
async () => {
const remaining = await sentinels.count();
if (remaining > 0) {
await sentinels
.first()
.scrollIntoViewIfNeeded({ timeout: 1_000 })
.catch(() => {
// Mounted between the count and the scroll.
});
}
return remaining;
},
{ timeout: 20_000 },
)
.toBe(0);
await page.evaluate(() => document.querySelector("main")?.scrollTo(0, 0));
}