From 06e4898c30feaedc471f97aba28ddb0d61379f4d Mon Sep 17 00:00:00 2001 From: Tudor Date: Tue, 14 Jul 2026 23:12:23 +0100 Subject: [PATCH] test(e2e): pick two same-phase schools for the compare journey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compare page's phase tabs put all-through schools (which carry KS4 data) on the secondary tab, so comparing an all-through school with a pure primary splits them across tabs and only the active tab renders its link. The test picked the first two 'primary' search hits without guaranteeing same phase, so it flaked whenever a search returned an all-through school first (e.g. URN 137306). Now selects two pure-Primary URNs via the API — deterministic and data-invariant. Verified against staging: was a 15.6s timeout, now passes in ~1.8s. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB --- e2e/tests/journeys.spec.ts | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/e2e/tests/journeys.spec.ts b/e2e/tests/journeys.spec.ts index 936dfe2..1fee453 100644 --- a/e2e/tests/journeys.spec.ts +++ b/e2e/tests/journeys.spec.ts @@ -19,6 +19,27 @@ function schoolLinks(page: Page) { return page.locator('a[href^="/school/"]'); } +/** + * Two URNs guaranteed to be pure-primary (same phase). The compare page's + * phase tabs split all-through schools (which carry KS4 data) onto the + * secondary tab, so picking two arbitrary "primary" search hits can land + * them on different tabs where only the active one renders. Selecting via + * the API by exact phase keeps both on the same tab. Data-invariant: uses + * whatever primaries the environment holds. + */ +async function twoPrimaryUrns(page: Page): Promise<[string, string]> { + const res = await page.request.get('/api/schools?search=primary&per_page=50'); + expect(res.ok()).toBeTruthy(); + const body = await res.json(); + const urns: string[] = (body.schools ?? []) + .filter((s: { phase?: string; rwm_expected_pct?: number | null }) => + s.phase === 'Primary' && s.rwm_expected_pct != null, + ) + .map((s: { urn: number }) => String(s.urn)); + expect(urns.length).toBeGreaterThanOrEqual(2); + return [urns[0], urns[1]]; +} + test('home page loads with hero search', async ({ page }) => { await page.goto('/'); await expect(page.locator('h1').first()).toBeVisible(); @@ -139,19 +160,13 @@ test('results map fullscreen falls back to an overlay on iOS', async ({ page }) }); test('comparing two schools shows the parent-first sections side by side', async ({ page }) => { - // Collect two school URNs from search results, then load the share URL - await searchByName(page, 'primary'); - await expect(schoolLinks(page).first()).toBeVisible({ timeout: 15_000 }); - const hrefs = await schoolLinks(page).evaluateAll((links) => - links.map((l) => (l as HTMLAnchorElement).getAttribute('href') || '') - ); - const urns = [...new Set(hrefs.map((h) => h.match(/\/school\/(\d+)/)?.[1]).filter(Boolean))]; - expect(urns.length).toBeGreaterThanOrEqual(2); + // Two same-phase (pure primary) schools so both stay on one tab. + const [urn0, urn1] = await twoPrimaryUrns(page); - await page.goto(`/compare?urns=${urns[0]},${urns[1]}`); + await page.goto(`/compare?urns=${urn0},${urn1}`); // Both schools' detail links should render in the comparison view - await expect(page.locator(`a[href*="${urns[0]}"]`).first()).toBeVisible({ timeout: 15_000 }); - await expect(page.locator(`a[href*="${urns[1]}"]`).first()).toBeVisible(); + await expect(page.locator(`a[href*="${urn0}"]`).first()).toBeVisible({ timeout: 15_000 }); + await expect(page.locator(`a[href*="${urn1}"]`).first()).toBeVisible(); // The parent-first sections render in order (data-invariant: headings only) for (const heading of [ -- 2.54.0