import { describe, expect, it } from 'vitest'; import { articleJsonLd, breadcrumbListJsonLd } from '#web-runtime/lib/structured-data'; import type { PageDocument } from '#web-runtime/types'; function page(overrides: Partial = {}): PageDocument { return { id: '61', status: 'published', locale: 'en', path: 'blog/api-webhooks', groupKey: 'blog-api-webhooks', layout: 'blog-item', title: 'Working with webhooks', seo: { title: 'Working with webhooks — Crux', description: 'How webhooks work.' }, breadcrumbs: [], blocks: [], publishedAt: '2026-06-23T13:28:30.697+00:00', updatedAt: '2026-08-13T13:28:30.698+00:00', ...overrides }; } describe('articleJsonLd', () => { it('marks up the dates and the hero image', () => { const media = { url: 'https://cdn.example.com/hero.jpg', alt: 'Hero' }; const data = articleJsonLd(page({ hero: { type: 'low', ctaItems: [], media } })); expect(data).toEqual({ '@context': 'https://schema.org', '@type': 'Article', 'headline': 'Working with webhooks — Crux', 'description': 'How webhooks work.', 'datePublished': '2026-06-23T13:28:30.697+00:00', 'dateModified': '2026-08-13T13:28:30.698+00:00', 'image': ['https://cdn.example.com/hero.jpg'], 'inLanguage': 'en' }); }); it('emits nothing without a publication date, rather than an Article a crawler will drop', () => { expect(articleJsonLd(page({ publishedAt: null }))).toBeNull(); }); it('omits dateModified when the page has never been changed since publishing', () => { const published = '2026-06-23T13:28:30.697+00:00'; const data = articleJsonLd(page({ publishedAt: published, updatedAt: published })); expect(data).not.toHaveProperty('dateModified'); expect(data).toMatchObject({ datePublished: published }); }); it('falls back to the page title and omits fields the page does not have', () => { const data = articleJsonLd(page({ seo: { title: '', description: '' } })); expect(data).toMatchObject({ headline: 'Working with webhooks' }); expect(data).not.toHaveProperty('description'); expect(data).not.toHaveProperty('image'); }); }); describe('breadcrumbListJsonLd', () => { it('numbers the trail from one and leaves the current page without a url', () => { const data = breadcrumbListJsonLd([ { label: 'Home', href: '/en' }, { label: 'Blog', href: '/en/blog' }, { label: 'Working with webhooks', href: '/en/blog/api-webhooks' } ]) as { itemListElement: Array> }; expect(data.itemListElement.map((item) => item['position'])).toEqual([1, 2, 3]); expect(data.itemListElement[0]).toHaveProperty('item'); expect(data.itemListElement[2]).not.toHaveProperty('item'); }); });