2026-09-14 20:45:50 +01:00
|
|
|
/**
|
|
|
|
|
* School pages had no BreadcrumbList and no links into the location layer.
|
|
|
|
|
* Both are fixed by the same data — the `places` array the API now returns —
|
|
|
|
|
* so they are tested together.
|
|
|
|
|
*/
|
|
|
|
|
import { schoolBreadcrumbJsonLd } from '@/lib/jsonld';
|
|
|
|
|
|
2026-09-14 20:54:59 +01:00
|
|
|
const essex = { kind: 'authority', slug: 'essex', name: 'Essex', count: 480, url: '/schools/authority/essex', phases: [] };
|
|
|
|
|
const brentwood = { kind: 'town', slug: 'brentwood', name: 'Brentwood', count: 37, url: '/schools/brentwood', phases: [] };
|
|
|
|
|
const outcode = { kind: 'outcode', slug: 'cm15', name: 'CM15', count: 12, url: '/schools/near/cm15', phases: [] };
|
2026-09-14 20:45:50 +01:00
|
|
|
|
|
|
|
|
describe('school breadcrumbs', () => {
|
|
|
|
|
it('reads home to authority to town to school', () => {
|
|
|
|
|
const ld = schoolBreadcrumbJsonLd({
|
|
|
|
|
name: 'Brentwood School', url: '/school/100000-brentwood-school',
|
|
|
|
|
places: [essex, brentwood],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(ld['@type']).toBe('BreadcrumbList');
|
|
|
|
|
expect(ld.itemListElement.map((i) => i.name))
|
|
|
|
|
.toEqual(['schoolcompare', 'Essex', 'Brentwood', 'Brentwood School']);
|
|
|
|
|
expect(ld.itemListElement.map((i) => i.position)).toEqual([1, 2, 3, 4]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('skips a level the school has no published place for', () => {
|
|
|
|
|
// A school whose town falls below the publish threshold has no town page.
|
|
|
|
|
// The trail closes over the gap rather than linking to a 404.
|
|
|
|
|
const ld = schoolBreadcrumbJsonLd({
|
|
|
|
|
name: 'Lone School', url: '/school/1-lone-school', places: [essex],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(ld.itemListElement.map((i) => i.name))
|
|
|
|
|
.toEqual(['schoolcompare', 'Essex', 'Lone School']);
|
|
|
|
|
expect(ld.itemListElement.map((i) => i.position)).toEqual([1, 2, 3]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('omits outcodes, which are not a place a breadcrumb reads through', () => {
|
|
|
|
|
// CM15 is a useful link in the module but nonsense in a trail: nobody
|
|
|
|
|
// navigates Essex → CM15 → school.
|
|
|
|
|
const ld = schoolBreadcrumbJsonLd({
|
|
|
|
|
name: 'Brentwood School', url: '/school/100000-brentwood-school',
|
|
|
|
|
places: [essex, brentwood, outcode],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(JSON.stringify(ld)).not.toContain('cm15');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('still produces a valid trail when the school has no places at all', () => {
|
|
|
|
|
const ld = schoolBreadcrumbJsonLd({
|
|
|
|
|
name: 'Orphan School', url: '/school/2-orphan-school', places: [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(ld.itemListElement.map((i) => i.name)).toEqual(['schoolcompare', 'Orphan School']);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('uses absolute urls, as every other entity on the site does', () => {
|
|
|
|
|
const ld = schoolBreadcrumbJsonLd({
|
|
|
|
|
name: 'Brentwood School', url: '/school/100000-brentwood-school',
|
|
|
|
|
places: [essex, brentwood],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const item of ld.itemListElement) {
|
|
|
|
|
expect(item.item).toMatch(/^https:\/\/www\.schoolcompare\.co\.uk\//);
|
|
|
|
|
}
|
|
|
|
|
// The root is the homepage: there is no /schools index page to link to.
|
|
|
|
|
expect(ld.itemListElement[0].item).toBe('https://www.schoolcompare.co.uk/');
|
|
|
|
|
});
|
|
|
|
|
});
|