/** * Last distance offered, rendered on both detail templates. * * The figure is the one number on these pages that a parent may act on — it is * easy to read as "we live inside the catchment, we will get a place". These * tests pin the things that stop it being read that way: the year is always * present, the caveat is always present, and the blanket "not available" * sentence appears only when it is actually true. */ import { screen, fireEvent } from '@testing-library/react'; import { renderSchoolDetail, renderSecondarySchoolDetail } from '../support/renderSchoolDetail'; import { primaryFixture, secondaryFixture } from '../support/schoolFixtures'; import type { SchoolAdmissionDistance } from '@/lib/types'; const cutoff = (over: Partial = {}): SchoolAdmissionDistance => ({ year: 2025, distance_m: 500, route_count: 1, la_name: 'Camden', distance_unit_raw: 'miles', ...over, }); describe('primary detail page', () => { it('shows the figure with the year it belongs to', () => { renderSchoolDetail({ ...primaryFixture, admissionDistance: cutoff({ distance_m: 772.49, year: 2024 }) }); expect(screen.getByText('0.48 miles')).toBeInTheDocument(); expect(screen.getByText(/Last distance offered/)).toHaveTextContent('September 2024'); }); it('keeps the figure and its metric support readable as two numbers', () => { // They are flex children with a CSS gap and nothing between them in the // text layer, which read as "0.48 miles770 m" to a screen reader and to any // text matcher. Cheap to lose again, so pinned. renderSchoolDetail({ ...primaryFixture, admissionDistance: cutoff({ distance_m: 772.49 }) }); const tile = document.querySelector('[class*="admissionsTileDistance"]')!; expect(tile.textContent).toMatch(/0\.48 miles\s+770 m/); expect(tile.textContent).not.toMatch(/miles\d/); }); it('never shows the figure without saying it is not a catchment', () => { renderSchoolDetail({ ...primaryFixture, admissionDistance: cutoff() }); expect(screen.getByText(/not a fixed catchment/)).toBeInTheDocument(); expect(screen.getByText(/moves every year/)).toBeInTheDocument(); }); it('flags that a banded school\'s figure is the widest of several routes', () => { renderSchoolDetail({ ...primaryFixture, admissionDistance: cutoff({ route_count: 4 }) }); expect(screen.getByText(/4 admission routes/)).toBeInTheDocument(); }); it('renders nothing distance-related when the LA publishes none', () => { renderSchoolDetail({ ...primaryFixture, admissionDistance: null }); expect(screen.queryByText(/Last distance offered/)).not.toBeInTheDocument(); expect(screen.queryByText(/not a fixed catchment/)).not.toBeInTheDocument(); }); it('carries the figure even with no EES admissions row', () => { // The two sources are independent; this school has a cut-off and no // admissions figures. Before this feature the section did not render at all. renderSchoolDetail({ ...primaryFixture, admissions: null, admissionsHistory: [], admissionDistance: cutoff({ distance_m: 1421.05 }), }); expect(screen.getByText('0.88 miles')).toBeInTheDocument(); }); }); describe('secondary detail page', () => { it('shows the figure with the year it belongs to', () => { renderSecondarySchoolDetail({ ...secondaryFixture, admissionDistance: cutoff({ distance_m: 3472.96 }) }); expect(screen.getByText('2.16 miles')).toBeInTheDocument(); expect(screen.getByText(/Last distance offered/)).toHaveTextContent('September 2025'); }); it('drops the blanket "not available" line once a distance exists', () => { renderSecondarySchoolDetail({ ...secondaryFixture, admissionDistance: cutoff() }); expect(screen.queryByText(/has not published a cut-off distance/)).not.toBeInTheDocument(); expect(screen.getByText(/not a fixed catchment/)).toBeInTheDocument(); }); it('names the authority that would hold the data when there is none', () => { // The old copy asserted "Historical distance cut-off data is not available // for this school" on every secondary page, including the ones whose // council does publish it. renderSecondarySchoolDetail({ ...secondaryFixture, admissionDistance: null }); expect(screen.getByText(/has not published a cut-off distance/)).toBeInTheDocument(); }); it('makes no claim about publication when the feature is switched off', () => { // Absent, not null. The API omits the key entirely while the // admission_distance flag is off, and "Islington has not published a // cut-off distance" is then a statement about us, not about Islington — // false wherever the authority does publish one. renderSecondarySchoolDetail({ ...secondaryFixture, admissionDistance: undefined }); expect(screen.queryByText(/has not published a cut-off distance/)).not.toBeInTheDocument(); expect(screen.queryByText(/Contact the admissions authority/)).not.toBeInTheDocument(); }); }); // ── The Distance section ─────────────────────────────────────────────── describe('Distance section', () => { it('appears for a school with a figure and coordinates', () => { const { container } = renderSchoolDetail({ ...primaryFixture, schoolInfo: { ...primaryFixture.schoolInfo, latitude: 51.5, longitude: -0.12 }, admissionDistance: cutoff({ distance_m: 700, year: 2026 }), }); expect(container.querySelector('#distance')).toBeInTheDocument(); expect(screen.getByText('How far away are you?')).toBeInTheDocument(); }); it('stays away when the school has no coordinates to measure from', () => { const { container } = renderSchoolDetail({ ...primaryFixture, schoolInfo: { ...primaryFixture.schoolInfo, latitude: null, longitude: null }, admissionDistance: cutoff({ distance_m: 700, year: 2026 }), }); expect(container.querySelector('#distance')).not.toBeInTheDocument(); }); it('stays away when no figure has been published', () => { const { container } = renderSchoolDetail({ ...primaryFixture, schoolInfo: { ...primaryFixture.schoolInfo, latitude: 51.5, longitude: -0.12 }, admissionDistance: null, }); expect(container.querySelector('#distance')).not.toBeInTheDocument(); }); it('shows no year-by-year record — that is held back as a paid feature', () => { // The page must not leak the history through a table, a chart or a strip of // per-year verdicts. The API no longer sends it either; this guards the // render side so a future component cannot quietly put it back. renderSchoolDetail({ ...primaryFixture, schoolInfo: { ...primaryFixture.schoolInfo, latitude: 51.5, longitude: -0.12 }, admissionDistance: cutoff({ distance_m: 700, year: 2026 }), }); // Scoped to the section: the page has other tables (the history section's). const section = document.querySelector('#distance')!; expect(section.querySelector('table')).toBeNull(); expect(screen.queryByText(/Last distance offered, by year/)).not.toBeInTheDocument(); expect(screen.queryByText(/Not published/)).not.toBeInTheDocument(); expect(screen.queryByText(/too few to read as a trend/)).not.toBeInTheDocument(); }); }); describe('secondary Distance section', () => { it('renders on the secondary template too', () => { const { container } = renderSecondarySchoolDetail({ ...secondaryFixture, schoolInfo: { ...secondaryFixture.schoolInfo, latitude: 51.5, longitude: -0.12 }, admissionDistance: cutoff({ distance_m: 3472.96, year: 2026 }), }); expect(container.querySelector('#distance')).toBeInTheDocument(); }); it('explains a selective school by how it admits rather than as missing data', () => { renderSecondarySchoolDetail({ ...secondaryFixture, schoolInfo: { ...secondaryFixture.schoolInfo, admissions_policy: 'Selective' }, admissionDistance: null, }); expect(screen.getByText(/ranked by the entrance test/)).toBeInTheDocument(); expect(screen.queryByText(/has not published a cut-off distance/)).not.toBeInTheDocument(); }); it('reads a consistently undersubscribed school as good news', () => { renderSecondarySchoolDetail({ ...secondaryFixture, admissionDistance: null, admissionsHistory: [ { year: 2022, oversubscribed: false }, { year: 2023, oversubscribed: false }, { year: 2024, oversubscribed: false }, ], }); expect(screen.getByText(/has not needed a distance cut-off/)).toBeInTheDocument(); }); });