import { describe, expect, it } from 'vitest'; import { normalizeSitemapEntries, sitemapLastPage } from '#web-runtime/data/normalize'; import { buildSitemap } from '#web-runtime/lib/sitemap'; import type { SitemapEntry } from '#web-runtime/types'; const origin = new URL('https://crux.example.com'); const publicPath = (locale: string, path: string) => `/${locale}${path ? `/${path}` : ''}`; function entry(overrides: Partial = {}): SitemapEntry { return { locale: 'en', path: 'about', groupKey: 'about', pageType: 'landing', publishedAt: '2026-01-01T00:00:00.000+00:00', updatedAt: '2026-02-01T00:00:00.000+00:00', ...overrides }; } describe('sitemap entry normalization', () => { it('reads the backend listing', () => { const entries = normalizeSitemapEntries({ items: [ { id: 7, locale: 'en', path: '/about/', groupKey: 'about', pageType: 'landing', publishedAt: '2026-01-01T00:00:00.000+00:00', updatedAt: null } ] }); expect(entries).toEqual([ { locale: 'en', path: 'about', groupKey: 'about', pageType: 'landing', publishedAt: '2026-01-01T00:00:00.000+00:00', updatedAt: null } ]); }); it('drops entries with no locale, which cannot become a URL', () => { expect(normalizeSitemapEntries({ items: [{ path: 'about' }] })).toEqual([]); }); it('survives a payload that is not a listing at all', () => { expect(normalizeSitemapEntries(null)).toEqual([]); expect(normalizeSitemapEntries({})).toEqual([]); expect(normalizeSitemapEntries({ items: 'nope' })).toEqual([]); }); it('reads the page count, defaulting to a single page', () => { expect(sitemapLastPage({ pagination: { lastPage: 57 } })).toBe(57); expect(sitemapLastPage({ pagination: { lastPage: 0 } })).toBe(1); expect(sitemapLastPage({})).toBe(1); expect(sitemapLastPage(null)).toBe(1); }); }); describe('buildSitemap', () => { it('emits absolute URLs against the configured origin', () => { const [item] = buildSitemap([entry()], origin, publicPath); expect(item?.url).toBe('https://crux.example.com/en/about'); }); it('uses the home path for a page with no path segment', () => { const [item] = buildSitemap([entry({ path: '', groupKey: 'home' })], origin, publicPath); expect(item?.url).toBe('https://crux.example.com/en'); }); it('reports lastModified from the update date, falling back to publication', () => { const [updated] = buildSitemap([entry()], origin, publicPath); const [neverUpdated] = buildSitemap([entry({ updatedAt: null })], origin, publicPath); const [undated] = buildSitemap( [entry({ updatedAt: null, publishedAt: null })], origin, publicPath ); expect(updated?.lastModified).toEqual(new Date('2026-02-01T00:00:00.000+00:00')); expect(neverUpdated?.lastModified).toEqual(new Date('2026-01-01T00:00:00.000+00:00')); expect(undated?.lastModified).toBeUndefined(); }); it('links translations of the same page to each other', () => { const sitemap = buildSitemap( [ entry({ locale: 'en', path: 'about' }), entry({ locale: 'de', path: 'ueber-uns' }), entry({ locale: 'uk', path: 'pro-nas' }) ], origin, publicPath ); expect(sitemap).toHaveLength(3); for (const item of sitemap) { expect(item.alternates?.languages).toEqual({ en: 'https://crux.example.com/en/about', de: 'https://crux.example.com/de/ueber-uns', uk: 'https://crux.example.com/uk/pro-nas' }); } }); it('omits the alternates block for a page that exists in one locale only', () => { const [item] = buildSitemap([entry()], origin, publicPath); expect(item?.alternates).toBeUndefined(); }); it('never groups pages that merely lack a group key', () => { const sitemap = buildSitemap( [entry({ groupKey: '', path: 'a' }), entry({ groupKey: '', path: 'b', locale: 'de' })], origin, publicPath ); expect(sitemap.every((item) => item.alternates === undefined)).toBe(true); }); });