Merge pull request 'fix(list/map): report-card schools badged as Report Card, not their old grade' (#63) from fix/list-map-report-card-signal into main
Stage (build -> staging -> E2E gate) / Build Backend (FastAPI) (push) Successful in 21s
Stage (build -> staging -> E2E gate) / Build Frontend (Next.js) (push) Successful in 54s
Stage (build -> staging -> E2E gate) / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 13s
Stage (build -> staging -> E2E gate) / Deploy to Staging (push) Successful in 1s
Stage (build -> staging -> E2E gate) / E2E Journeys against Staging (push) Successful in 41s
Stage (build -> staging -> E2E gate) / Build Backend (FastAPI) (push) Successful in 21s
Stage (build -> staging -> E2E gate) / Build Frontend (Next.js) (push) Successful in 54s
Stage (build -> staging -> E2E gate) / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 13s
Stage (build -> staging -> E2E gate) / Deploy to Staging (push) Successful in 1s
Stage (build -> staging -> E2E gate) / E2E Journeys against Staging (push) Successful in 41s
Reviewed-on: #63
This commit was merged in pull request #63.
This commit is contained in:
@@ -172,6 +172,7 @@ _MAIN_QUERY = text("""
|
|||||||
foi.ofsted_grade,
|
foi.ofsted_grade,
|
||||||
foi.ofsted_date,
|
foi.ofsted_date,
|
||||||
foi.ofsted_framework,
|
foi.ofsted_framework,
|
||||||
|
foi.ofsted_rc_date,
|
||||||
l.local_authority_name AS local_authority,
|
l.local_authority_name AS local_authority,
|
||||||
l.local_authority_code,
|
l.local_authority_code,
|
||||||
l.address_line1 AS address1,
|
l.address_line1 AS address1,
|
||||||
@@ -256,7 +257,12 @@ _MAIN_QUERY = text("""
|
|||||||
-- Fall back to the ungraded-inspection grade when no graded grade exists.
|
-- Fall back to the ungraded-inspection grade when no graded grade exists.
|
||||||
COALESCE(overall_effectiveness, ungraded_grade) AS ofsted_grade,
|
COALESCE(overall_effectiveness, ungraded_grade) AS ofsted_grade,
|
||||||
inspection_date AS ofsted_date,
|
inspection_date AS ofsted_date,
|
||||||
framework AS ofsted_framework
|
framework AS ofsted_framework,
|
||||||
|
-- Report-card signal for list/map badges: non-null only when the
|
||||||
|
-- latest inspection carries report-card grades. framework is the
|
||||||
|
-- raw event grouping ("Schools - S5"), never "ReportCard", so it
|
||||||
|
-- can't be used to detect report cards.
|
||||||
|
rc_inspection_date AS ofsted_rc_date
|
||||||
FROM marts.fact_ofsted_inspection
|
FROM marts.fact_ofsted_inspection
|
||||||
ORDER BY urn, inspection_date DESC NULLS LAST
|
ORDER BY urn, inspection_date DESC NULLS LAST
|
||||||
) foi ON s.urn = foi.urn
|
) foi ON s.urn = foi.urn
|
||||||
|
|||||||
@@ -550,6 +550,7 @@ SCHOOL_COLUMNS = [
|
|||||||
"ofsted_grade",
|
"ofsted_grade",
|
||||||
"ofsted_date",
|
"ofsted_date",
|
||||||
"ofsted_framework",
|
"ofsted_framework",
|
||||||
|
"ofsted_rc_date",
|
||||||
"latitude",
|
"latitude",
|
||||||
"longitude",
|
"longitude",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -80,6 +80,33 @@ test('searching by postcode returns nearby schools', async ({ page }) => {
|
|||||||
await expect(schoolLinks(page).first()).toBeVisible({ timeout: 15_000 });
|
await expect(schoolLinks(page).first()).toBeVisible({ timeout: 15_000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a report-card school shows a Report Card badge in search results, not its old grade', async ({ page }) => {
|
||||||
|
// List/map badges keyed off ofsted_grade (the carried-forward legacy grade)
|
||||||
|
// and never reached the report-card branch, so report-card schools were
|
||||||
|
// labelled by their old grade (e.g. "Outstanding · 2021"). The list now
|
||||||
|
// carries ofsted_rc_date and the badge treats a report card as winning.
|
||||||
|
const RC_URN = 138690; // Barclay Primary — has a Nov-2025+ report card
|
||||||
|
const res = await page.request.get(`/api/schools?search=Barclay%20Primary&page_size=5`);
|
||||||
|
expect(res.ok()).toBeTruthy();
|
||||||
|
const barclay = ((await res.json()).schools ?? []).find(
|
||||||
|
(s: { urn: number }) => s.urn === RC_URN,
|
||||||
|
);
|
||||||
|
// Hard assertions, not test.skip: if the backend stops exposing
|
||||||
|
// ofsted_rc_date for this report-card school, that IS the regression this
|
||||||
|
// test exists to catch, so it must fail loudly rather than skip.
|
||||||
|
expect(barclay, 'Barclay must appear in the search results').toBeTruthy();
|
||||||
|
expect(
|
||||||
|
barclay.ofsted_rc_date,
|
||||||
|
'the list must expose ofsted_rc_date for a report-card school',
|
||||||
|
).toBeTruthy();
|
||||||
|
|
||||||
|
await searchByName(page, 'Barclay Primary');
|
||||||
|
// The Barclay row must be present…
|
||||||
|
await expect(page.locator(`a[href*="${RC_URN}"]`).first()).toBeVisible({ timeout: 15_000 });
|
||||||
|
// …badged as a Report Card, not its carried-forward "Outstanding" grade.
|
||||||
|
await expect(page.getByText(/Report Card ·/).first()).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
test('school detail page renders name and performance data', async ({ page }) => {
|
test('school detail page renders name and performance data', async ({ page }) => {
|
||||||
await searchByName(page, 'primary');
|
await searchByName(page, 'primary');
|
||||||
const firstSchool = schoolLinks(page).first();
|
const firstSchool = schoolLinks(page).first();
|
||||||
|
|||||||
@@ -130,9 +130,23 @@ describe('buildOfstedListBadge', () => {
|
|||||||
expect(badge.cssClass).toBe('ofsted2');
|
expect(badge.cssClass).toBe('ofsted2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns Report Card badge when framework is ReportCard', () => {
|
it('returns a Report Card badge when ofsted_rc_date is present', () => {
|
||||||
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_date: '2025-11-01', ofsted_framework: 'ReportCard' });
|
const badge = buildOfstedListBadge({ ofsted_grade: null, ofsted_rc_date: '2026-02-03' });
|
||||||
expect(badge.label).toBe('Report Card · 2025');
|
expect(badge.label).toBe('Report Card · 2026');
|
||||||
|
expect(badge.cssClass).toBe('ofstedRc');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('a report card wins over a carried-forward legacy grade', () => {
|
||||||
|
// The production bug: a report-card school (e.g. Barclay) also carries a
|
||||||
|
// carried-forward legacy grade (ofsted_grade), which used to win and label
|
||||||
|
// the pin "Outstanding · 2021" instead of "Report Card · 2026".
|
||||||
|
const badge = buildOfstedListBadge({
|
||||||
|
ofsted_grade: 1,
|
||||||
|
ofsted_date: '2021-10-07',
|
||||||
|
ofsted_framework: 'Schools - S5',
|
||||||
|
ofsted_rc_date: '2026-02-03',
|
||||||
|
});
|
||||||
|
expect(badge.label).toBe('Report Card · 2026');
|
||||||
expect(badge.cssClass).toBe('ofstedRc');
|
expect(badge.cssClass).toBe('ofstedRc');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ interface PopupBadge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildPopupBadge(school: School): PopupBadge {
|
function buildPopupBadge(school: School): PopupBadge {
|
||||||
|
// A report card wins over any carried-forward legacy grade — its presence is
|
||||||
|
// signalled by ofsted_rc_date (the list has no full report_card object, and
|
||||||
|
// ofsted_framework is the raw event grouping, never "ReportCard").
|
||||||
|
if (school.ofsted_rc_date) {
|
||||||
|
const rcYear = new Date(school.ofsted_rc_date).getFullYear();
|
||||||
|
return { label: `Report Card · ${rcYear}`, style: 'background:#5a3a6e;color:#fff' };
|
||||||
|
}
|
||||||
const year = school.ofsted_date ? new Date(school.ofsted_date).getFullYear() : null;
|
const year = school.ofsted_date ? new Date(school.ofsted_date).getFullYear() : null;
|
||||||
const yearStr = year ? ` · ${year}` : '';
|
const yearStr = year ? ` · ${year}` : '';
|
||||||
if (school.ofsted_grade) {
|
if (school.ofsted_grade) {
|
||||||
@@ -55,9 +62,6 @@ function buildPopupBadge(school: School): PopupBadge {
|
|||||||
};
|
};
|
||||||
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
return { label: `${labels[school.ofsted_grade]}${yearStr}`, style: colours[school.ofsted_grade] };
|
||||||
}
|
}
|
||||||
if (school.ofsted_framework === 'ReportCard') {
|
|
||||||
return { label: `Report Card${yearStr}`, style: 'background:#5a3a6e;color:#fff' };
|
|
||||||
}
|
|
||||||
return { label: 'Not yet inspected', style: 'background:#e0e0e0;color:#666' };
|
return { label: 'Not yet inspected', style: 'background:#e0e0e0;color:#666' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ export interface School {
|
|||||||
|
|
||||||
// Ofsted (for list view — summary only)
|
// Ofsted (for list view — summary only)
|
||||||
ofsted_grade?: 1 | 2 | 3 | 4 | null;
|
ofsted_grade?: 1 | 2 | 3 | 4 | null;
|
||||||
|
/** Report-card inspection date (Nov 2025+); non-null identifies a report
|
||||||
|
* card in the list/map, where the full report_card object isn't available. */
|
||||||
|
ofsted_rc_date?: string | null;
|
||||||
ofsted_date?: string | null;
|
ofsted_date?: string | null;
|
||||||
ofsted_framework?: string | null;
|
ofsted_framework?: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-6
@@ -691,9 +691,12 @@ export interface OfstedListBadge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the Ofsted badge for a school card in the list/map view.
|
* Build the Ofsted badge for a school card in the list/map view.
|
||||||
* Three states:
|
* States, in priority order:
|
||||||
|
* - Report Card school (ofsted_rc_date set): "Report Card · YYYY" in purple.
|
||||||
|
* Checked FIRST so it wins over any carried-forward legacy grade — the
|
||||||
|
* list has no full report_card object, and ofsted_framework is the raw
|
||||||
|
* event grouping ("Schools - S5"), never "ReportCard".
|
||||||
* - OEIF school (ofsted_grade set): grade word + year, colour-keyed
|
* - OEIF school (ofsted_grade set): grade word + year, colour-keyed
|
||||||
* - ReportCard school (ofsted_framework === 'ReportCard'): "Report Card · YYYY" in purple
|
|
||||||
* - Inspected without an overall grade (OEIF post-Sept-2024, where Ofsted no
|
* - Inspected without an overall grade (OEIF post-Sept-2024, where Ofsted no
|
||||||
* longer issues an overall judgement): "Inspected · YYYY" — mirrors the
|
* longer issues an overall judgement): "Inspected · YYYY" — mirrors the
|
||||||
* detail page's hero chip so a school never reads as both inspected and
|
* detail page's hero chip so a school never reads as both inspected and
|
||||||
@@ -704,7 +707,16 @@ export function buildOfstedListBadge(school: {
|
|||||||
ofsted_grade?: 1 | 2 | 3 | 4 | null;
|
ofsted_grade?: 1 | 2 | 3 | 4 | null;
|
||||||
ofsted_date?: string | null;
|
ofsted_date?: string | null;
|
||||||
ofsted_framework?: string | null;
|
ofsted_framework?: string | null;
|
||||||
|
ofsted_rc_date?: string | null;
|
||||||
}): OfstedListBadge {
|
}): OfstedListBadge {
|
||||||
|
// A report card wins over any carried-forward legacy grade — signalled by
|
||||||
|
// ofsted_rc_date. ofsted_framework is the raw event grouping ("Schools -
|
||||||
|
// S5"), never "ReportCard", so it can't detect report cards.
|
||||||
|
if (school.ofsted_rc_date) {
|
||||||
|
const rcYear = new Date(school.ofsted_rc_date).getFullYear();
|
||||||
|
return { label: `Report Card · ${rcYear}`, cssClass: 'ofstedRc' };
|
||||||
|
}
|
||||||
|
|
||||||
const year = school.ofsted_date
|
const year = school.ofsted_date
|
||||||
? new Date(school.ofsted_date).getFullYear()
|
? new Date(school.ofsted_date).getFullYear()
|
||||||
: null;
|
: null;
|
||||||
@@ -723,10 +735,6 @@ export function buildOfstedListBadge(school: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (school.ofsted_framework === 'ReportCard') {
|
|
||||||
return { label: `Report Card${yearStr}`, cssClass: 'ofstedRc' };
|
|
||||||
}
|
|
||||||
|
|
||||||
// An inspection is on record (date or framework present) but carries no
|
// An inspection is on record (date or framework present) but carries no
|
||||||
// overall grade — a post-Sept-2024 OEIF inspection. Distinct from a school
|
// overall grade — a post-Sept-2024 OEIF inspection. Distinct from a school
|
||||||
// that has genuinely never been inspected.
|
// that has genuinely never been inspected.
|
||||||
|
|||||||
Reference in New Issue
Block a user