2026-09-02 16:28:58 +01:00
|
|
|
/**
|
|
|
|
|
* 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.
|
2026-09-08 17:12:25 +01:00
|
|
|
const ld = blogPostingJsonLd(post, { namedAuthor: true });
|
2026-09-02 16:28:58 +01:00
|
|
|
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');
|
|
|
|
|
});
|
|
|
|
|
|
2026-09-08 17:12:25 +01:00
|
|
|
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');
|
|
|
|
|
});
|
|
|
|
|
|
2026-09-02 16:28:58 +01:00
|
|
|
it('carries a self-referencing canonical url and the publish date', () => {
|
2026-09-08 17:12:25 +01:00
|
|
|
const ld = blogPostingJsonLd(post, { namedAuthor: true });
|
2026-09-02 16:28:58 +01:00
|
|
|
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',
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|