Merge pull request 'fix(places): stop the place titles doubling the brand' (#117) from fix/place-title-brand-doubling into main
Stage (build -> staging -> E2E gate) / Build Backend (FastAPI) (push) Successful in 12s
Stage (build -> staging -> E2E gate) / Build Frontend (Next.js) (push) Successful in 50s
Stage (build -> staging -> E2E gate) / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Stage (build -> staging -> E2E gate) / Deploy to Staging (push) Successful in 1s
Stage (build -> staging -> E2E gate) / E2E Journeys against Staging (push) Failing after 1m30s

Reviewed-on: #117
This commit was merged in pull request #117.
This commit is contained in:
tudor committed 2026-08-21 20:53:14 +00:00
commit 6d79bd3331
6 files changed
+37 -5

No files matched your search

+17
View File
@@ -1868,3 +1868,20 @@ test('phase variants are submitted in the places sitemap', async ({ page }) => {
const xml = await (await page.request.get('/sitemaps/places-1.xml')).text();
expect(xml).toMatch(/\/schools\/[a-z0-9-]+\/primary</);
});
test('no page title repeats the brand', async ({ page }) => {
// The root layout appends '| schoolcompare' to a plain-string title. Any
// route whose title already carries the brand must opt out with
// `absolute`, or it ships '... | schoolcompare | schoolcompare' — which is
// how ~2,600 place pages first went out.
const res = await page.request.get('/api/places');
const { places } = await res.json();
const town = places.find((p: { kind: string }) => p.kind === 'town');
for (const path of ['/', '/rankings', '/admissions', `/schools/${town.slug}`]) {
await page.goto(path);
const title = await page.title();
const brands = (title.match(/schoolcompare/gi) ?? []).length;
expect(brands, `${path} repeats the brand: ${title}`).toBeLessThanOrEqual(1);
}
});
+13 -1
View File
@@ -14,7 +14,7 @@ jest.mock('@/lib/places', () => ({
describe('place page metadata', () => {
it('titles the page the way the place is searched', async () => {
const m = await placeMeta({ params: Promise.resolve({ place: 'brentwood' }) });
expect(m.title).toMatch(/schools in brentwood/i);
expect((m.title as { absolute: string }).absolute).toMatch(/schools in brentwood/i);
});
it('canonicalises to its own path on the www host', async () => {
@@ -23,6 +23,18 @@ describe('place page metadata', () => {
.toBe('https://www.schoolcompare.co.uk/schools/brentwood');
});
it('opts out of the layout template, which would double the brand', () => {
// The root layout appends '| schoolcompare' to a plain string title, and
// these titles already carry it — every place page shipped reading
// '... | schoolcompare | schoolcompare' until this was made absolute.
return placeMeta({ params: Promise.resolve({ place: 'brentwood' }) })
.then((m) => {
expect(typeof m.title).toBe('object');
expect((m.title as { absolute: string }).absolute)
.not.toMatch(/schoolcompare.*schoolcompare/);
});
});
it('an unknown place gets a not-found title rather than inventing one', async () => {
const m = await placeMeta({ params: Promise.resolve({ place: 'atlantis' }) });
expect(m.title).toMatch(/not found/i);
@@ -37,7 +37,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
const word = phase === 'secondary' ? 'Secondary' : 'Primary';
const { name } = detail.place;
return {
title: `${word} Schools in ${name} — Ranked | schoolcompare`,
title: { absolute: `${word} Schools in ${name} — Ranked | schoolcompare` },
description:
`Every ${phase} school in ${name} ranked by results, with Ofsted grades and `
+ `the local average against England.`,
+4 -1
View File
@@ -53,7 +53,10 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { name, count } = detail.place;
return {
title: `Schools in ${name} — Compare ${count} Schools | schoolcompare`,
// absolute: the root layout's template appends '| schoolcompare' to a
// plain string, and this title already carries it. Without this every
// place title read '... | schoolcompare | schoolcompare'.
title: { absolute: `Schools in ${name} — Compare ${count} Schools | schoolcompare` },
description:
`Every school in ${name} ranked by SATs and GCSE results, with Ofsted grades, `
+ `the local average against England, and how close you had to live to get a place.`,
@@ -43,7 +43,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { name, count } = detail.place;
return {
title: `Schools in ${name} — Local Authority | schoolcompare`,
title: { absolute: `Schools in ${name} — Local Authority | schoolcompare` },
description:
`All ${count} schools in the ${name} local authority, ranked by SATs and GCSE `
+ `results, with Ofsted grades and the authority average against England.`,
@@ -38,7 +38,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { name, count } = detail.place;
return {
title: `Schools near ${name} | schoolcompare`,
title: { absolute: `Schools near ${name} | schoolcompare` },
description:
`${count} schools in the ${name} postcode district, ranked by results, with `
+ `Ofsted grades and how close you had to live to get a place.`,