/** * compareLogic encodes the expert-reviewed comprehension rules for the * compare screen: report-card summarisation (safeguarding never counted), * three-regime Ofsted display, one consistent admissions chip metric, * CI-based progress banding, verdict chips and dot-strip geometry. */ import { OFSTED_LEGACY_GRADES, ofstedDisplay, progressBand, rcAreaLabel, stripPositions, summariseAdmissions, summariseReportCard, verdict, } from '@/lib/compareLogic'; import type { OfstedInspection, SchoolAdmissions } from '@/lib/types'; function ofsted(partial: Partial): OfstedInspection { return { framework: null, inspection_date: null, inspection_type: null, overall_effectiveness: null, quality_of_education: null, behaviour_attitudes: null, personal_development: null, leadership_management: null, early_years_provision: null, previous_overall: null, rc_safeguarding_met: null, rc_inclusion: null, rc_curriculum_teaching: null, rc_achievement: null, rc_attendance_behaviour: null, rc_personal_development: null, rc_leadership_governance: null, rc_early_years: null, rc_sixth_form: null, ...partial, }; } const REPORT_CARD = { rc_achievement: { code: 2, label: 'Strong standard' }, rc_curriculum_teaching: { code: 2, label: 'Strong standard' }, rc_personal_development: { code: 2, label: 'Strong standard' }, rc_leadership_governance: { code: 2, label: 'Strong standard' }, rc_inclusion: { code: 3, label: 'Expected standard' }, rc_early_years: { code: 3, label: 'Expected standard' }, rc_attendance_behaviour: { code: 4, label: 'Needs attention' }, }; describe('summariseReportCard', () => { it('counts graded areas best-first and NAMES problem areas', () => { const s = summariseReportCard( ofsted({ report_card: REPORT_CARD, rc_safeguarding_met: true }), ); expect(s.counts).toEqual([ { label: 'Strong standard', count: 4 }, { label: 'Expected standard', count: 2 }, ]); expect(s.problems).toEqual([ { areaLabel: 'Attendance & behaviour', label: 'Needs attention' }, ]); expect(s.safeguarding).toBe('met'); expect(s.allClear).toBe(false); }); it('never counts safeguarding as a graded area', () => { const s = summariseReportCard( ofsted({ report_card: { rc_achievement: { code: 3, label: 'Expected standard' } }, rc_safeguarding_met: true, }), ); const total = s.counts.reduce((n, c) => n + c.count, 0); expect(total).toBe(1); }); it('is allClear when everything is Expected standard or better and safeguarding met', () => { const s = summariseReportCard( ofsted({ report_card: { rc_achievement: { code: 3, label: 'Expected standard' }, rc_inclusion: { code: 1, label: 'Exceptional' }, }, rc_safeguarding_met: true, }), ); expect(s.allClear).toBe(true); expect(s.counts[0]).toEqual({ label: 'Exceptional', count: 1 }); }); it('passes labels through from the API — never invents wording', () => { const s = summariseReportCard( ofsted({ report_card: { rc_inclusion: { code: 4, label: 'Needs attention' } } }), ); expect(JSON.stringify(s)).not.toContain('Attention needed'); }); }); describe('ofstedDisplay', () => { it('prefers the report card over any legacy grade', () => { const d = ofstedDisplay( ofsted({ overall_effectiveness: 2, report_card: REPORT_CARD }), ); expect(d.kind).toBe('report_card'); }); it('distinguishes graded from carried-forward grades', () => { const graded = ofstedDisplay( ofsted({ overall_effectiveness: 1, grade_source: 'graded' }), ); expect(graded).toMatchObject({ kind: 'graded', gradeLabel: 'Outstanding', carriedForward: false }); const carried = ofstedDisplay( ofsted({ overall_effectiveness: 2, grade_source: 'ungraded_carried_forward' }), ); expect(carried).toMatchObject({ kind: 'carried_forward', gradeLabel: 'Good', carriedForward: true }); }); it('handles missing data', () => { expect(ofstedDisplay(null).kind).toBe('none'); expect(ofstedDisplay(ofsted({})).kind).toBe('none'); }); it('identifies transitional inspections without overall grades', () => { const transitional = ofstedDisplay( ofsted({ overall_effectiveness: null, inspection_date: '2024-11-05' }), ); expect(transitional.kind).toBe('transitional'); }); it('uses the four legacy grade words', () => { expect(OFSTED_LEGACY_GRADES).toEqual({ 1: 'Outstanding', 2: 'Good', 3: 'Requires improvement', 4: 'Inadequate', }); }); }); describe('rcAreaLabel', () => { it('maps rc keys to the mockups’ area labels', () => { expect(rcAreaLabel('rc_attendance_behaviour')).toBe('Attendance & behaviour'); expect(rcAreaLabel('rc_curriculum_teaching')).toBe('Curriculum & teaching'); expect(rcAreaLabel('rc_leadership_governance')).toBe('Leadership & governance'); }); }); describe('summariseAdmissions', () => { function admissions(partial: Partial): SchoolAdmissions { return { year: 202627, places_offered: null, total_applications: null, first_preference_offer_pct: null, oversubscribed: null, ...partial, }; } it('97% → good chip with the mockup wording', () => { const s = summariseAdmissions( admissions({ first_preference_offer_pct: 96.98, total_applications: 457, places_offered: 180 }), ); expect(s.chip).toEqual({ tone: 'good', text: '97% of first choices offered' }); expect(s.interest).toBe('Named on 457 forms · 180 places'); }); it('73% → warn chip "Over 1 in 4 first choices missed out"', () => { const s = summariseAdmissions(admissions({ first_preference_offer_pct: 73.4 })); expect(s.chip).toEqual({ tone: 'warn', text: 'Over 1 in 4 first choices missed out' }); }); it('100% → "All first choices offered"', () => { const s = summariseAdmissions(admissions({ first_preference_offer_pct: 100 })); expect(s.chip).toEqual({ tone: 'good', text: 'All first choices offered' }); }); it('no data → null chip and interest', () => { const s = summariseAdmissions(null); expect(s.chip).toBeNull(); expect(s.interest).toBeNull(); }); }); describe('progressBand', () => { it('CI entirely above zero → above', () => { expect(progressBand(1.2, 0.4, 2.0)).toBe('above'); }); it('CI entirely below zero → below', () => { expect(progressBand(-1.2, -2.0, -0.4)).toBe('below'); }); it('CI straddling zero → average', () => { expect(progressBand(0.3, -0.5, 1.1)).toBe('average'); }); it('missing CI → null (no naive thresholding)', () => { expect(progressBand(1.2, null, null)).toBeNull(); expect(progressBand(null, null, null)).toBeNull(); }); }); describe('verdict', () => { it('above / close / below with a 2pp tolerance', () => { expect(verdict(87, 62)).toBe('above'); expect(verdict(61, 62)).toBe('close'); expect(verdict(40, 62)).toBe('below'); }); }); describe('stripPositions', () => { it('maps a custom domain', () => { const pts = stripPositions([106], 100, 120); expect(pts[0].pos).toBe(30); }); it('flips a colliding label above', () => { const pts = stripPositions([91, 92], 0, 100); const sorted = [...pts].sort((a, b) => a.value - b.value); expect(sorted[0].labelAbove).toBe(false); expect(sorted[1].labelAbove).toBe(true); }); it('skips nulls and keeps school indices', () => { const pts = stripPositions([50, null, 70], 0, 100); expect(pts).toHaveLength(2); expect(pts.map((p) => p.schoolIndex)).toEqual([0, 2]); }); it('clamps out-of-domain values', () => { const pts = stripPositions([95], 100, 120); expect(pts[0].pos).toBe(0); }); }); describe('latestValues', () => { const data = { '1': { yearly_data: [ { year: 202324, rwm_expected_pct: 75 }, { year: 202425, rwm_expected_pct: 87 }, ], }, '2': { yearly_data: [ { year: 202324, rwm_expected_pct: 82 }, { year: 202425, rwm_expected_pct: null }, ], }, }; it('takes the latest non-null value per school in urn order', async () => { const { latestValues } = await import('@/lib/compareLogic'); expect(latestValues(data, [1, 2], 'rwm_expected_pct')).toEqual([87, 82]); }); it('returns null for unknown schools and metrics', async () => { const { latestValues } = await import('@/lib/compareLogic'); expect(latestValues(data, [3], 'rwm_expected_pct')).toEqual([null]); expect(latestValues(data, [1], 'nope')).toEqual([null]); }); });