2026-10-02 22:02:32 +01:00
|
|
|
|
/**
|
2026-10-02 22:59:45 +01:00
|
|
|
|
* The school header: one fact line (phase, ages, type, pupils), then flags
|
|
|
|
|
|
* only for what applies, then the address and the details.
|
2026-10-02 22:02:32 +01:00
|
|
|
|
*
|
|
|
|
|
|
* nursery_provision is GIAS text, not a boolean: "Has Nursery Classes",
|
|
|
|
|
|
* "No Nursery Classes" or "Not applicable". Tested for truthiness, every one
|
|
|
|
|
|
* of those read as a nursery, so secondaries aged 11–18 showed "Nursery".
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-10-02 22:59:45 +01:00
|
|
|
|
import { screen, within } from '@testing-library/react';
|
2026-10-02 22:16:49 +01:00
|
|
|
|
import type { School } from '@/lib/types';
|
2026-10-02 22:02:32 +01:00
|
|
|
|
import { primaryFixture, secondaryFixture } from '../support/schoolFixtures';
|
|
|
|
|
|
import { renderSchoolDetail, renderSecondarySchoolDetail } from '../support/renderSchoolDetail';
|
|
|
|
|
|
|
|
|
|
|
|
jest.mock('@/lib/analytics', () => ({
|
|
|
|
|
|
track: jest.fn(),
|
|
|
|
|
|
getNavigationSource: () => 'direct',
|
|
|
|
|
|
}));
|
|
|
|
|
|
jest.mock('@/components/PerformanceChart', () => ({
|
|
|
|
|
|
PerformanceChart: () => <div data-testid="performance-chart" />,
|
|
|
|
|
|
}));
|
|
|
|
|
|
jest.mock('@/components/SatsChart', () => ({
|
|
|
|
|
|
__esModule: true,
|
|
|
|
|
|
default: () => <div data-testid="sats-chart" />,
|
|
|
|
|
|
}));
|
|
|
|
|
|
jest.mock('@/components/AdmissionsTrendChart', () => ({
|
|
|
|
|
|
__esModule: true,
|
|
|
|
|
|
default: () => <div data-testid="admissions-trend-chart" />,
|
|
|
|
|
|
}));
|
|
|
|
|
|
jest.mock('@/components/SchoolHeroMap', () => ({
|
|
|
|
|
|
SchoolHeroMap: () => <div data-testid="hero-map" />,
|
|
|
|
|
|
__esModule: true,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2026-10-02 22:16:49 +01:00
|
|
|
|
function withSchool<T extends { schoolInfo: School }>(fixture: T, info: Partial<School>): T {
|
2026-10-02 22:02:32 +01:00
|
|
|
|
return { ...fixture, schoolInfo: { ...fixture.schoolInfo, ...info } };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-02 22:59:45 +01:00
|
|
|
|
const flagList = () => screen.queryByRole('list', { name: 'Admission and provision' });
|
|
|
|
|
|
const flagLabels = () => within(flagList()!).getAllByRole('listitem').map((li) => li.textContent);
|
|
|
|
|
|
|
|
|
|
|
|
describe('school header fact line', () => {
|
|
|
|
|
|
it('states phase, ages, type and pupils, in that order', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { type_group: 'state' }));
|
|
|
|
|
|
const line = screen.getByText('Ages 4–11').parentElement!;
|
|
|
|
|
|
expect(line).toHaveTextContent(/^PrimaryAges 4–11State school420 pupils$/);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("prints the register's type name for a type in no group", () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { type_group: null, school_type: 'Secure units' }));
|
|
|
|
|
|
expect(screen.getByText('Secure units')).toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('no longer prints the GIAS establishment type', () => {
|
|
|
|
|
|
renderSecondarySchoolDetail(withSchool(secondaryFixture, { type_group: 'state' }));
|
|
|
|
|
|
expect(screen.queryByText('Academy converter')).not.toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('school header flags', () => {
|
|
|
|
|
|
it('shows no flag list for a school with nothing to flag', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { type_group: 'state' }));
|
|
|
|
|
|
expect(flagList()).not.toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('lists who-can-apply flags, then what the school offers', () => {
|
|
|
|
|
|
renderSecondarySchoolDetail(withSchool(secondaryFixture, {
|
|
|
|
|
|
type_group: 'independent', admissions_policy: 'Selective', gender: 'Girls',
|
|
|
|
|
|
religious_denomination: 'Church of England', has_sixth_form: true,
|
|
|
|
|
|
}));
|
|
|
|
|
|
expect(flagLabels()).toEqual(['Fee-paying', 'Selective', "Girls' school", 'Church of England', 'Sixth form']);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('shows Nursery class when GIAS says the school has nursery classes', () => {
|
2026-10-02 22:02:32 +01:00
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { nursery_provision: 'Has Nursery Classes' }));
|
2026-10-02 22:59:45 +01:00
|
|
|
|
expect(flagLabels()).toEqual(['Nursery class']);
|
2026-10-02 22:02:32 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it.each(['No Nursery Classes', 'Not applicable', null])(
|
2026-10-02 22:59:45 +01:00
|
|
|
|
'shows no nursery flag when GIAS says %p',
|
2026-10-02 22:02:32 +01:00
|
|
|
|
(value) => {
|
|
|
|
|
|
renderSecondarySchoolDetail(withSchool(secondaryFixture, { nursery_provision: value }));
|
2026-10-02 22:59:45 +01:00
|
|
|
|
expect(screen.queryByText(/^Nursery/)).not.toBeInTheDocument();
|
2026-10-02 22:02:32 +01:00
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
it.each([['Girls', "Girls' school"], ['Boys', "Boys' school"]])(
|
|
|
|
|
|
'labels a %s school with a plural possessive',
|
|
|
|
|
|
(gender, label) => {
|
|
|
|
|
|
renderSecondarySchoolDetail(withSchool(secondaryFixture, { gender }));
|
|
|
|
|
|
expect(screen.getByText(label)).toBeInTheDocument();
|
|
|
|
|
|
expect(screen.queryByText(/'s school/)).not.toBeInTheDocument();
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
it('says nothing for a mixed school', () => {
|
|
|
|
|
|
renderSecondarySchoolDetail(withSchool(secondaryFixture, { gender: 'Mixed' }));
|
2026-10-02 22:16:49 +01:00
|
|
|
|
expect(screen.queryByText(/^(Girls|Boys|Mixed)'s? school$/)).not.toBeInTheDocument();
|
2026-10-02 22:02:32 +01:00
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-10-02 22:59:45 +01:00
|
|
|
|
|
|
|
|
|
|
describe('school header address', () => {
|
|
|
|
|
|
it('names the council after the postcode', () => {
|
|
|
|
|
|
renderSchoolDetail(primaryFixture);
|
|
|
|
|
|
expect(screen.getByText(/TE1 1ST · Westshire/)).toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('leaves the council out when the address already names it', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { local_authority: 'Testville' }));
|
|
|
|
|
|
expect(screen.queryByText(/· Testville/)).not.toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('school header details', () => {
|
|
|
|
|
|
const detailed = {
|
|
|
|
|
|
headteacher_name: 'Mrs A Head', capacity: 426, county: 'Surrey',
|
|
|
|
|
|
parliamentary_constituency: 'Putney', religious_denomination: 'Church of England',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
it('drops county, constituency and religious character', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, detailed));
|
|
|
|
|
|
expect(screen.queryByText('County:')).not.toBeInTheDocument();
|
|
|
|
|
|
expect(screen.queryByText('Constituency:')).not.toBeInTheDocument();
|
|
|
|
|
|
expect(screen.queryByText('Religious character:')).not.toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('shows the capacity', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, detailed));
|
|
|
|
|
|
expect(screen.getByText('Capacity:').parentElement).toHaveTextContent('Capacity: 426');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('names an academy trust', () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { trust_name: 'BURNTWOOD TRUST' }));
|
|
|
|
|
|
expect(screen.getByText('Academy trust:').parentElement).toHaveTextContent('BURNTWOOD TRUST');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("hides a trust that has the school's own name", () => {
|
|
|
|
|
|
renderSchoolDetail(withSchool(primaryFixture, { trust_name: 'TEST PRIMARY SCHOOL' }));
|
|
|
|
|
|
expect(screen.queryByText('Academy trust:')).not.toBeInTheDocument();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|