Files

131 lines
4.1 KiB
TypeScript

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> = {}): 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);
});
});