Files
school_compare/nextjs-app/__tests__/lib/schoolSections.test.ts
T
TudorandClaude Opus 5 4e0d8bcf87 feat(web): render similar schools on both detail templates
Inside SchoolDetailShell rather than after it, because the sticky nav's
scroll-spy finds sections with getElementById and can only reach one that
lives in the shell. Last in the order, and last in the nav, because the two
must agree or the nav links to an anchor that was never rendered.

hasSimilarSchools is optional on NavItemsInput, matching hasLocation beside
it: absent has to mean "no section", and making it required would have
churned ten unrelated call sites for no added safety.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 22:42:59 +01:00

211 lines
7.5 KiB
TypeScript

import {
computeSchoolFlags, buildNavItems,
computeSecondaryFlags, buildSecondaryNavItems,
} from '@/lib/schoolSections';
import {
primaryFixture, secondaryFixture, allThroughFixture, specialFixture,
} from '../support/schoolFixtures';
describe('computeSchoolFlags', () => {
it('treats an all-through school as both primary-capable and secondary', () => {
const f = computeSchoolFlags(allThroughFixture);
expect(f.isAllThrough).toBe(true);
expect(f.isSecondary).toBe(true);
expect(f.hasKS2Results).toBe(true);
expect(f.hasKS4Results).toBe(true);
});
it('classifies an ordinary primary', () => {
const f = computeSchoolFlags(primaryFixture);
expect(f.isPrimary).toBe(true);
expect(f.isSecondary).toBe(false);
expect(f.hasKS2Results).toBe(true);
expect(f.hasKS4Results).toBe(false);
});
it('classifies an ordinary secondary', () => {
const f = computeSchoolFlags(secondaryFixture);
expect(f.isSecondary).toBe(true);
expect(f.isAllThrough).toBe(false);
expect(f.hasKS4Results).toBe(true);
});
it('suppresses the KS2 comparison for a special school', () => {
const f = computeSchoolFlags(specialFixture);
expect(f.isSpecial).toBe(true);
expect(f.suppressKs2Comparison).toBe(true);
expect(f.suppressKs4Comparison).toBe(true);
});
it('treats an all-zero KS2 row as a placeholder', () => {
const f = computeSchoolFlags(specialFixture);
expect(f.ks2Placeholder).toBe(true);
});
it('does not suppress comparison for an ordinary primary', () => {
const f = computeSchoolFlags(primaryFixture);
expect(f.isSpecial).toBe(false);
expect(f.suppressKs2Comparison).toBe(false);
});
it('detects a gender split only when census counts are present', () => {
expect(computeSchoolFlags(primaryFixture).hasGenderSplit).toBe(true);
expect(
computeSchoolFlags({ ...primaryFixture, census: null }).hasGenderSplit,
).toBe(false);
});
});
describe('buildNavItems', () => {
it('omits sections with no data', () => {
const flags = computeSchoolFlags(specialFixture);
const ids = buildNavItems(flags, {
ofsted: null, admissions: null, admissionDistance: null, yearlyDataLength: 1,
}).map((n) => n.id);
expect(ids).not.toContain('ofsted');
expect(ids).not.toContain('admissions');
expect(ids).toContain('history');
});
it('labels the results section by phase', () => {
const label = (fixture: any) => {
const flags = computeSchoolFlags(fixture);
return buildNavItems(flags, {
ofsted: fixture.ofsted,
admissions: fixture.admissions,
admissionDistance: null,
yearlyDataLength: fixture.yearlyData.length,
}).find((n) => n.id === 'results')?.label;
};
expect(label(primaryFixture)).toBe('SATs');
expect(label(secondaryFixture)).toBe('GCSEs');
expect(label(allThroughFixture)).toBe('Results');
});
it('opens the admissions entry for a cut-off distance with no EES admissions', () => {
// 3% of the schools that render have one source and not the other. The nav
// condition and the section's render condition have to agree, or the sticky
// nav links to an anchor that was never rendered.
const flags = computeSchoolFlags(specialFixture);
const ids = buildNavItems(flags, {
ofsted: null,
admissions: null,
admissionDistance: { year: 2025, distance_m: 500, route_count: 1, la_name: 'Camden', distance_unit_raw: 'miles' },
yearlyDataLength: 1,
}).map((n) => n.id);
expect(ids).toContain('admissions');
});
it('keeps the engagement-led ordering', () => {
const flags = computeSchoolFlags(primaryFixture);
const ids = buildNavItems(flags, {
ofsted: primaryFixture.ofsted,
admissions: primaryFixture.admissions,
admissionDistance: null,
yearlyDataLength: primaryFixture.yearlyData.length,
}).map((n) => n.id);
expect(ids).toEqual([
'ofsted', 'results', 'admissions', 'inclusion',
'history', 'school-life', 'local-area', 'finances',
]);
});
});
describe('computeSecondaryFlags', () => {
it('reads results and sixth form from the secondary fixture', () => {
const f = computeSecondaryFlags(secondaryFixture);
expect(f.hasResults).toBe(true);
expect(f.hasSixthForm).toBe(false);
expect(f.hasWellbeing).toBe(true);
});
it('reports sixth form when GIAS flags it', () => {
expect(computeSecondaryFlags(allThroughFixture).hasSixthForm).toBe(true);
});
it('suppresses the comparison for a special school', () => {
const f = computeSecondaryFlags(specialFixture);
expect(f.isSpecial).toBe(true);
expect(f.suppressComparison).toBe(true);
});
it('does not flag Progress 8 as suspended for pre-2024/25 cohorts', () => {
expect(computeSecondaryFlags(secondaryFixture).p8Suspended).toBe(false);
});
});
describe('buildSecondaryNavItems', () => {
it('uses the secondary section ids', () => {
const flags = computeSecondaryFlags(secondaryFixture);
const ids = buildSecondaryNavItems(flags, {
ofsted: secondaryFixture.ofsted,
admissions: secondaryFixture.admissions,
admissionDistance: null,
yearlyDataLength: secondaryFixture.yearlyData.length,
}).map((n) => n.id);
expect(ids).toEqual(['ofsted', 'gcse', 'admissions', 'history', 'wellbeing', 'finances']);
});
it('opens the admissions entry for a cut-off distance alone', () => {
const flags = computeSecondaryFlags(secondaryFixture);
const ids = buildSecondaryNavItems(flags, {
ofsted: null,
admissions: null,
admissionDistance: { year: 2025, distance_m: 2400, route_count: 4, la_name: 'Islington', distance_unit_raw: 'miles' },
yearlyDataLength: 1,
}).map((n) => n.id);
expect(ids).toContain('admissions');
});
it('gates History on more than one year, unlike the primary page', () => {
const flags = computeSecondaryFlags(secondaryFixture);
const ids = buildSecondaryNavItems(flags, {
ofsted: null, admissions: null, admissionDistance: null, yearlyDataLength: 1,
}).map((n) => n.id);
expect(ids).not.toContain('history');
});
});
describe('the similar-schools nav item', () => {
const navInput = {
ofsted: null, admissions: null, admissionDistance: null,
hasLocation: true, yearlyDataLength: 1,
};
it('appears on both templates when the section renders', () => {
const primary = computeSchoolFlags(primaryFixture);
const secondary = computeSecondaryFlags(secondaryFixture);
const input = { ...navInput, hasSimilarSchools: true };
expect(buildNavItems(primary, input).map((i) => i.id)).toContain('similar');
expect(buildSecondaryNavItems(secondary, input).map((i) => i.id)).toContain('similar');
});
it('is absent when the section does not render', () => {
const primary = computeSchoolFlags(primaryFixture);
const secondary = computeSecondaryFlags(secondaryFixture);
const input = { ...navInput, hasSimilarSchools: false };
expect(buildNavItems(primary, input).map((i) => i.id)).not.toContain('similar');
expect(buildSecondaryNavItems(secondary, input).map((i) => i.id)).not.toContain('similar');
});
it('is absent when nothing says either way', () => {
const primary = computeSchoolFlags(primaryFixture);
expect(buildNavItems(primary, navInput).map((i) => i.id)).not.toContain('similar');
});
it('comes last, because the section renders last', () => {
const primary = computeSchoolFlags(primaryFixture);
const ids = buildNavItems(primary, { ...navInput, hasSimilarSchools: true }).map((i) => i.id);
expect(ids[ids.length - 1]).toBe('similar');
});
});