Files
school_compare/nextjs-app/__tests__/lib/compareChartData.test.ts
TudorandClaude Fable 5 f3fa12806b
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m2s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 10s
PR Checks / Build Frontend (no push) (pull_request) Successful in 49s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 3m8s
fix(compare): expert should-fixes S1-S4, S6 — banded chips, P8 reason, KS4 gap caption, all-through framing, cohort sizes
S1: first-choice chip banded (More than half / About 1 in 3 / Over 1 in 4
missed out) so a 44%-offered grammar isn't understated by half.
S2: Progress 8 explains its absence for 2024/25+ cohorts (no KS2 baseline,
COVID) instead of a bare 'No data'.
S3: KS4 trend charts get their own honest gap caption (2019/20-2020/21
unpublished; later years not in our dataset yet); y-axis 'Value'→'Score';
buildCompareChart exposes englandOnlyYears.
S4: all-through schools labelled in chips, rail caption says 'N schools ·
<phase> view' for mixed baskets, whole-school roll no longer judged
against the single-phase median, community section carries an all-ages
caveat.
S6 (spec §8.5): disadvantaged attainment shows the cohort behind it
('of ~50 disadvantaged pupils').

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
2026-07-17 17:41:12 +01:00

94 lines
3.7 KiB
TypeScript

/**
* buildCompareChart: every selected school must produce a rendered series
* (regression guard for the production bug where a third school's line
* vanished), the x-axis must include cancelled/unpublished years as real
* gaps (never compressing time), and the England overlay renders dashed
* with no gap-bridging.
*/
import { buildCompareChart, fillAcademicYears } from '@/lib/compareChartData';
import type { ComparisonData } from '@/lib/types';
function school(urn: number, years: Array<[number, number | null]>): ComparisonData {
return {
school_info: { urn, school_name: `School ${urn}` } as ComparisonData['school_info'],
yearly_data: years.map(([year, v]) => ({ year, rwm_expected_pct: v })) as ComparisonData['yearly_data'],
};
}
const THREE_SCHOOLS = {
'1': school(1, [[201819, 87], [202223, 87], [202425, 87]]),
'2': school(2, [[201819, 88], [202223, 88], [202425, 92]]),
'3': school(3, [[201819, 69], [202223, 62], [202425, 79]]),
};
const SCHOOL_LIST = [1, 2, 3].map((urn) => ({ urn, school_name: `School ${urn}` }));
describe('fillAcademicYears', () => {
it('fills every academic year between min and max', () => {
expect(fillAcademicYears([201819, 202223])).toEqual([
201819, 201920, 202021, 202122, 202223,
]);
});
});
describe('buildCompareChart', () => {
it('renders one series per selected school — none silently dropped', () => {
const chart = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct');
expect(chart.schoolDatasets).toHaveLength(3);
for (const ds of chart.schoolDatasets) {
expect(ds.data.some((v) => v != null)).toBe(true);
}
});
it('handles float years from the API (202425.0 style)', () => {
const floaty = {
'1': school(1, [[201819.0 as number, 80], [202425.0 as number, 85]]),
};
const chart = buildCompareChart(floaty, [SCHOOL_LIST[0]], 'rwm_expected_pct');
expect(chart.schoolDatasets[0].data.filter((v) => v != null)).toHaveLength(2);
});
it('includes cancelled/unpublished years as null gaps, not compressed time', () => {
const chart = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct');
expect(chart.years).toContain(201920);
expect(chart.years).toContain(202122);
const idx = chart.years.indexOf(202021);
expect(chart.schoolDatasets[0].data[idx]).toBeNull();
});
it('adds a dashed England overlay when national data is supplied', () => {
const chart = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct', {
201819: 64.9,
202122: 58.7,
202223: 59.5,
202425: 62.1,
});
expect(chart.englandDataset).not.toBeNull();
const eng = chart.englandDataset!;
expect(eng.label).toBe('England average');
expect(eng.borderDash).toEqual([5, 4]);
expect(eng.spanGaps).toBe(false);
// England has a value for 2021/22 even though schools do not
expect(eng.data[chart.years.indexOf(202122)]).toBe(58.7);
});
it('lists England-only years so the component can caption dashed-only stretches', () => {
const chart = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct', {
202122: 58.7,
});
expect(chart.englandOnlyYears).toEqual([202122]);
const none = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct');
expect(none.englandOnlyYears).toEqual([]);
});
it('flags the unpublished 2021/22 school-level year when England has data but schools do not', () => {
const withNational = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct', {
202122: 58.7,
});
expect(withNational.showUnpublished202122Note).toBe(true);
const withoutNational = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct');
expect(withoutNational.showUnpublished202122Note).toBe(false);
});
});