/** * The blog index imports getCachedPayload, which pulls in Payload — ESM-only, * and next/jest will not transform node_modules. Mocking that one module keeps * the page's metadata testable without loading the CMS; the mock is never * called, because `metadata` is a static export evaluated at import time. */ jest.mock('@/lib/payload', () => ({ getCachedPayload: jest.fn() })); import { metadata } from '@/app/(frontend)/blog/page'; import { blogPostingJsonLd, breadcrumbJsonLd } from '@/lib/jsonld'; const post = { title: 'What the data cannot tell you', slug: 'what-the-data-cannot-tell-you', excerpt: 'Results describe one year group on a handful of days.', publishedAt: '2026-09-15T00:00:00.000Z', }; describe('/blog metadata', () => { it('canonicalises to the bare path', () => { expect(metadata.alternates?.canonical) .toBe('https://www.schoolcompare.co.uk/blog'); }); }); describe('BlogPosting structured data', () => { it('names the same Person entity the about page declares', () => { // By @id, not by repeating the person: search engines must resolve every // post and the about page to one author entity, or the site has several. const ld = blogPostingJsonLd(post, { namedAuthor: true }); expect(ld['@type']).toBe('BlogPosting'); expect(ld.author['@id']).toBe('https://www.schoolcompare.co.uk/about#tudor'); expect(ld.publisher['@id']).toBe('https://www.schoolcompare.co.uk#organization'); }); it('attributes to the organization when the about page is dark', () => { /* * The two flags are independent, so blog-on-about-off is a reachable * state. The Person entity lives at /about#tudor and that URL 404s while * the flag is dark, so claiming it would declare an author that resolves * to nothing — worse for the blog's credibility than having no named * author at all. Attribute to the publisher instead. */ const ld = blogPostingJsonLd(post, { namedAuthor: false }); expect(ld.author['@id']).toBe('https://www.schoolcompare.co.uk#organization'); expect(JSON.stringify(ld)).not.toContain('/about'); }); it('carries a self-referencing canonical url and the publish date', () => { const ld = blogPostingJsonLd(post, { namedAuthor: true }); expect(ld.url).toBe( 'https://www.schoolcompare.co.uk/blog/what-the-data-cannot-tell-you', ); expect(ld.datePublished).toBe('2026-09-15T00:00:00.000Z'); }); }); describe('breadcrumbs', () => { it('places the post under the blog index', () => { const ld = breadcrumbJsonLd(post); expect(ld.itemListElement[0].item).toBe('https://www.schoolcompare.co.uk/blog'); expect(ld.itemListElement[1].item).toBe( 'https://www.schoolcompare.co.uk/blog/what-the-data-cannot-tell-you', ); }); });