Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 13s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 54s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
A school inspected under the OEIF framework after September 2024 has an inspection on record (ofsted_date set) but no overall_effectiveness grade, since Ofsted no longer issues an overall judgement. buildOfstedListBadge had no branch for this and fell through to "Not yet inspected", while the detail page's hero chip correctly reported it as inspected — so the same school read two contradictory ways. Add an "Inspected · YYYY" branch that fires when an inspection is on record (date or framework present) but no grade and not a Report Card, mirroring the hero chip's fallback. Genuinely un-inspected schools (all Ofsted fields null) still show "Not yet inspected". Add an .ofstedInspected badge style (neutral slate) distinct from the grey pending state, and cover both cases with tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
5.1 KiB
TypeScript
158 lines
5.1 KiB
TypeScript
/**
|
|
* Utility Functions Tests
|
|
*/
|
|
|
|
import {
|
|
formatPercentage,
|
|
formatProgress,
|
|
calculateTrend,
|
|
isValidPostcode,
|
|
debounce,
|
|
buildOfstedListBadge,
|
|
} from '@/lib/utils';
|
|
|
|
describe('formatPercentage', () => {
|
|
it('formats percentages correctly', () => {
|
|
expect(formatPercentage(75.5)).toBe('75.5%');
|
|
expect(formatPercentage(100)).toBe('100.0%');
|
|
expect(formatPercentage(0)).toBe('0.0%');
|
|
});
|
|
|
|
it('handles null values', () => {
|
|
expect(formatPercentage(null)).toBe('-');
|
|
});
|
|
});
|
|
|
|
describe('formatProgress', () => {
|
|
it('formats progress scores correctly', () => {
|
|
expect(formatProgress(2.5)).toBe('+2.5');
|
|
expect(formatProgress(-1.3)).toBe('-1.3');
|
|
expect(formatProgress(0)).toBe('0.0');
|
|
});
|
|
|
|
it('handles null values', () => {
|
|
expect(formatProgress(null)).toBe('-');
|
|
});
|
|
});
|
|
|
|
describe('calculateTrend', () => {
|
|
it('calculates upward trend', () => {
|
|
expect(calculateTrend(75, 70)).toBe('up');
|
|
});
|
|
|
|
it('calculates downward trend', () => {
|
|
expect(calculateTrend(70, 75)).toBe('down');
|
|
});
|
|
|
|
it('calculates same trend', () => {
|
|
expect(calculateTrend(75, 75)).toBe('same');
|
|
});
|
|
|
|
it('handles null previous value', () => {
|
|
expect(calculateTrend(75, null)).toBe('same');
|
|
});
|
|
|
|
it('handles null current value', () => {
|
|
expect(calculateTrend(null, 75)).toBe('same');
|
|
});
|
|
});
|
|
|
|
describe('isValidPostcode', () => {
|
|
it('validates correct UK postcodes', () => {
|
|
expect(isValidPostcode('SW1A 1AA')).toBe(true);
|
|
expect(isValidPostcode('M1 1AE')).toBe(true);
|
|
expect(isValidPostcode('B33 8TH')).toBe(true);
|
|
});
|
|
|
|
it('rejects invalid postcodes', () => {
|
|
expect(isValidPostcode('INVALID')).toBe(false);
|
|
expect(isValidPostcode('12345')).toBe(false);
|
|
expect(isValidPostcode('')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('debounce', () => {
|
|
jest.useFakeTimers();
|
|
|
|
it('delays function execution', () => {
|
|
const mockFn = jest.fn();
|
|
const debouncedFn = debounce(mockFn, 300);
|
|
|
|
debouncedFn('test');
|
|
expect(mockFn).not.toHaveBeenCalled();
|
|
|
|
jest.advanceTimersByTime(300);
|
|
expect(mockFn).toHaveBeenCalledWith('test');
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('cancels previous calls', () => {
|
|
const mockFn = jest.fn();
|
|
const debouncedFn = debounce(mockFn, 300);
|
|
|
|
debouncedFn('first');
|
|
jest.advanceTimersByTime(150);
|
|
debouncedFn('second');
|
|
jest.advanceTimersByTime(150);
|
|
debouncedFn('third');
|
|
jest.advanceTimersByTime(300);
|
|
|
|
expect(mockFn).toHaveBeenCalledWith('third');
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
describe('buildOfstedListBadge', () => {
|
|
it('returns grade word + year for OEIF Outstanding', () => {
|
|
const badge = buildOfstedListBadge({ ofsted_grade: 1, ofsted_date: '2023-11-15', ofsted_framework: 'OEIF' });
|
|
expect(badge.label).toBe('Outstanding · 2023');
|
|
expect(badge.cssClass).toBe('ofsted1');
|
|
});
|
|
|
|
it('returns grade word for each OEIF grade', () => {
|
|
expect(buildOfstedListBadge({ ofsted_grade: 2, ofsted_date: '2022-05-01' }).label).toBe('Good · 2022');
|
|
expect(buildOfstedListBadge({ ofsted_grade: 3, ofsted_date: '2021-01-01' }).label).toBe('Req. Improvement · 2021');
|
|
expect(buildOfstedListBadge({ ofsted_grade: 4, ofsted_date: '2020-03-01' }).label).toBe('Inadequate · 2020');
|
|
});
|
|
|
|
it('returns grade word without year when date is missing', () => {
|
|
const badge = buildOfstedListBadge({ ofsted_grade: 2, ofsted_date: null });
|
|
expect(badge.label).toBe('Good');
|
|
expect(badge.cssClass).toBe('ofsted2');
|
|
});
|
|
|
|
it('returns Report Card badge when framework is ReportCard', () => {
|
|
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_date: '2025-11-01', ofsted_framework: 'ReportCard' });
|
|
expect(badge.label).toBe('Report Card · 2025');
|
|
expect(badge.cssClass).toBe('ofstedRc');
|
|
});
|
|
|
|
it('returns an "Inspected" badge for an OEIF inspection with no overall grade (post-Sept-2024)', () => {
|
|
// Inspected after Sept 2024: inspection on record (date + framework) but
|
|
// Ofsted no longer issues an overall grade. Must NOT read as "Not yet inspected".
|
|
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_date: '2024-11-01', ofsted_framework: 'OEIF' });
|
|
expect(badge.label).toBe('Inspected · 2024');
|
|
expect(badge.cssClass).toBe('ofstedInspected');
|
|
});
|
|
|
|
it('returns an "Inspected" badge without a year when the grade is missing and date is absent but a record exists', () => {
|
|
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_date: null, ofsted_framework: 'OEIF' });
|
|
expect(badge.label).toBe('Inspected');
|
|
expect(badge.cssClass).toBe('ofstedInspected');
|
|
});
|
|
|
|
it('returns pending badge when no grade and no inspection on record', () => {
|
|
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_date: null, ofsted_framework: null });
|
|
expect(badge.label).toBe('Not yet inspected');
|
|
expect(badge.cssClass).toBe('ofstedPending');
|
|
});
|
|
|
|
it('returns pending badge when all fields are undefined', () => {
|
|
const badge = buildOfstedListBadge({});
|
|
expect(badge.label).toBe('Not yet inspected');
|
|
expect(badge.cssClass).toBe('ofstedPending');
|
|
});
|
|
});
|