import assert from 'node:assert/strict' import test from 'node:test' import { htmlSitemapOption } from '../lib/options.ts' import { SITEMAP_PAGE_PREFIX, seoSitemapPages, type SitemapPagesInput } from '../lib/sitemapPages.ts' const files = { overview: '/layer/SitemapPage.vue', group: '/layer/SitemapGroupPage.vue' } const query = { form: 'query' as const, param: 'page', segments: { pl: 'strona', en: 'page' } } const path = { form: 'path' as const, param: 'page', segments: { pl: 'strona', en: 'page' } } const input = (over: Partial = {}): SitemapPagesInput => ({ htmlSitemap: htmlSitemapOption({ paths: { pl: '/mapa-strony', en: '/sitemap' } }), pagination: query, pages: [{ path: '/', name: 'index' }], files, ...over, }) const summary = (routes: Array<{ name?: string; path: string }>) => routes.map((r) => `${r.name} ${r.path}`) test('seoSitemapPages: without i18n, one overview and one group page per locale', () => { const out = seoSitemapPages(input()) assert.deepEqual(summary(out.routes), [ 'seo-sitemap-pl /mapa-strony', 'seo-sitemap-group-pl /mapa-strony/:group', 'seo-sitemap-en /sitemap', 'seo-sitemap-group-en /sitemap/:group', ]) assert.deepEqual(out.skipped, []) assert.deepEqual(out.routes[0]!.meta, { seoSitemap: { locale: 'pl' } }) assert.equal(out.routes[0]!.file, files.overview) assert.equal(out.routes[1]!.file, files.group) assert.ok(out.routes.every((r) => r.name!.startsWith(SITEMAP_PAGE_PREFIX))) }) test('seoSitemapPages: the path form adds the page route with the locale segment', () => { const out = seoSitemapPages(input({ pagination: path })) assert.deepEqual(summary(out.routes).filter((s) => s.includes('group-page')), [ 'seo-sitemap-group-page-pl /mapa-strony/:group/strona/:page(\\d+)', 'seo-sitemap-group-page-en /sitemap/:group/page/:page(\\d+)', ]) // a locale without a segment falls back to the param const de = seoSitemapPages(input({ pagination: path, htmlSitemap: htmlSitemapOption({ paths: { de: '/seitenuebersicht' } }) })) assert.ok(summary(de.routes).includes('seo-sitemap-group-page-de /seitenuebersicht/:group/page/:page(\\d+)')) }) test('seoSitemapPages: with i18n each route is named for its own locale, once, at the configured path (L4 WR-05)', () => { const i18n = { strategy: 'prefix_except_default', defaultLocale: 'en', locales: [{ code: 'en' }, { code: 'pl' }] } const out = seoSitemapPages(input({ i18n, htmlSitemap: htmlSitemapOption({ paths: { en: '/sitemap', pl: '/pl/mapa-strony' } }) })) assert.deepEqual(summary(out.routes), [ 'seo-sitemap-en___en /sitemap', 'seo-sitemap-group-en___en /sitemap/:group', 'seo-sitemap-pl___pl /pl/mapa-strony', 'seo-sitemap-group-pl___pl /pl/mapa-strony/:group', ]) // no copy under another locale's name or prefix assert.ok(!out.routes.some((r) => /___pl$/.test(r.name!) && r.meta.seoSitemap.locale !== 'pl')) assert.ok(!out.routes.some((r) => r.path.startsWith('/pl/sitemap'))) // a custom separator; no_prefix leaves the names alone const sep = seoSitemapPages(input({ i18n: { ...i18n, routesNameSeparator: '__' } })) assert.ok(sep.routes.every((r) => r.name!.endsWith(`__${r.meta.seoSitemap.locale}`))) const noPrefix = seoSitemapPages(input({ i18n: { ...i18n, strategy: 'no_prefix' } })) assert.deepEqual(noPrefix.routes.map((r) => r.name), ['seo-sitemap-pl', 'seo-sitemap-group-pl', 'seo-sitemap-en', 'seo-sitemap-group-en']) }) test('seoSitemapPages: an app page at the path keeps it (taken)', () => { const out = seoSitemapPages(input({ pages: [{ path: '/', name: 'index' }, { path: '/mapa-strony', name: 'mapa-strony' }] })) assert.deepEqual(out.skipped, [{ locale: 'pl', path: '/mapa-strony', reason: 'taken' }]) assert.deepEqual(out.routes.map((r) => r.name), ['seo-sitemap-en', 'seo-sitemap-group-en']) // a nested page with the same full path is taken too const nested = seoSitemapPages(input({ pages: [{ path: '/sitemap', name: 'sm', children: [{ path: '', name: 'sm-index' }] }] })) assert.deepEqual(nested.skipped.map((s) => s.locale), ['en']) }) test('seoSitemapPages: a root catch-all skips every locale unless overCatchAll (L4 WR-04)', () => { const pages = [{ path: '/', name: 'index' }, { path: '/:slug(.*)*', name: 'slug' }] const out = seoSitemapPages(input({ pages })) assert.deepEqual(out.routes, []) assert.deepEqual(out.skipped, [ { locale: 'pl', path: '/mapa-strony', reason: 'catch-all' }, { locale: 'en', path: '/sitemap', reason: 'catch-all' }, ]) const over = seoSitemapPages(input({ pages, htmlSitemap: htmlSitemapOption({ paths: { pl: '/mapa-strony', en: '/sitemap' }, overCatchAll: true }) })) assert.equal(over.routes.length, 4) assert.deepEqual(over.skipped, []) }) test('seoSitemapPages: a prefixed catch-all skips only the paths it covers', () => { const pages = [{ path: '/pl/:slug(.*)*', name: 'pl-slug' }] const out = seoSitemapPages(input({ pages, htmlSitemap: htmlSitemapOption({ paths: { pl: '/pl/mapa-strony', en: '/sitemap' } }) })) assert.deepEqual(out.skipped, [{ locale: 'pl', path: '/pl/mapa-strony', reason: 'catch-all' }]) assert.deepEqual(out.routes.map((r) => r.name), ['seo-sitemap-en', 'seo-sitemap-group-en']) // the i18n copy of a root catch-all (/pl/... and /...) covers both const localized = [{ path: '/:slug(.*)*', name: 'slug___en' }, { path: '/pl/:slug(.*)*', name: 'slug___pl' }] assert.equal(seoSitemapPages(input({ pages: localized })).routes.length, 0) // a page with one parameter is not a catch-all assert.equal(seoSitemapPages(input({ pages: [{ path: '/:slug', name: 'slug' }] })).routes.length, 4) }) test('seoSitemapPages: htmlSitemap false answers nothing; earlier layer routes are not "taken"', () => { assert.deepEqual(seoSitemapPages(input({ htmlSitemap: false })), { routes: [], skipped: [] }) const again = seoSitemapPages(input({ pages: [{ path: '/mapa-strony', name: 'seo-sitemap-pl', file: files.overview }] })) assert.equal(again.routes.length, 4) assert.deepEqual(again.skipped, []) }) test('htmlSitemapOption: overCatchAll is a boolean, default false', () => { assert.deepEqual(htmlSitemapOption({ paths: { pl: '/mapa-strony' } }), { paths: { pl: '/mapa-strony' }, overCatchAll: false }) assert.deepEqual(htmlSitemapOption({ paths: { pl: '/mapa-strony' }, overCatchAll: true }), { paths: { pl: '/mapa-strony' }, overCatchAll: true }) assert.deepEqual(htmlSitemapOption({ paths: {}, overCatchAll: 'yes' }), { paths: {}, overCatchAll: false }) })