From 75cc100336a4889104a07d2305c97f5ad823eb76 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Wed, 4 Nov 2026 19:47:18 +0100 Subject: [PATCH] test: usePagination hrefs, head links and page count; drift pattern forms - the query and path forms from the resolve answer, the site answer and the layer option, page 1 unnumbered - prev and next links at the ends, %pages% from the page count - routeServes reads {param} and :param alike and ignores the query part --- tests/routes.test.ts | 9 +++ tests/usePagination.test.ts | 106 ++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 tests/usePagination.test.ts diff --git a/tests/routes.test.ts b/tests/routes.test.ts index aec0f37..982c023 100644 --- a/tests/routes.test.ts +++ b/tests/routes.test.ts @@ -115,3 +115,12 @@ test('driftWarnings: segments and param, a switched-off layer sitemap, a switche assert.deepEqual(driftWarnings({ site: { html_sitemap: { enabled: false, paths: { pl: '/x' } } }, routes, ...layer }), []) assert.deepEqual(driftWarnings({ site: {}, routes, ...layer }), []) }) + +test('routeServes normalises CMS patterns: {param} and :param alike, the query part ignored', () => { + const route = { pattern: '/blog/:slug', catchAll: false } + assert.equal(routeServes(route, '/blog/{slug}'), true) + assert.equal(routeServes(route, '/blog/:slug'), true) + assert.equal(routeServes(route, '/blog/{slug}?page={page}'), true) + assert.equal(routeServes(route, '/blog/{category}/{slug}'), false) + assert.equal(routeServes({ pattern: '/docs/**', catchAll: true }, '/docs/{a}/{b}'), true) +}) diff --git a/tests/usePagination.test.ts b/tests/usePagination.test.ts new file mode 100644 index 0000000..fc50a7f --- /dev/null +++ b/tests/usePagination.test.ts @@ -0,0 +1,106 @@ +// usePagination (D-40 to D-42, UI-SPEC L2) with the Nuxt composables it +// calls stubbed on globalThis: the page hrefs in the form the resolve +// answer, the site answer or the layer option names; the prev and next +// head links at the ends; the number of pages handed to the CMS head, +// whose %pages% seoFillPages replaces. +import assert from 'node:assert/strict' +import test from 'node:test' +import { computed, ref, toValue, watch } from 'vue' +import { seoFillPages } from '../app/utils/seo.ts' + +interface Stubs { + fullPath: string + answer: unknown + site: unknown + option?: unknown +} + +const g = globalThis as Record +let heads: Array<() => { link: Array<{ rel: string; href: string }> }> = [] +const states = new Map>() + +function stub(s: Stubs) { + heads = [] + states.clear() + Object.assign(g, { + computed, + toValue, + watch, + useRoute: () => ({ fullPath: s.fullPath }), + useSeoAnswer: () => ref(s.answer), + useRuntimeConfig: () => ({ public: { seo: s.option === undefined ? {} : { pagination: s.option } } }), + useNuxtData: () => ({ data: ref(s.site) }), + useState: (key: string, init: () => unknown) => { + if (!states.has(key)) states.set(key, ref(init())) + return states.get(key) + }, + useHead: (input: { value: { link: Array<{ rel: string; href: string }> } }) => heads.push(() => input.value), + }) +} + +const { usePagination, useSeoPages } = await import('../app/composables/usePagination.ts') + +test('the query form from the resolve answer: page 1 unnumbered, other parameters kept', () => { + stub({ fullPath: '/blog?sort=new&page=2', answer: { locale: 'pl', pagination: { form: 'query', param: 'page', segment: '' } }, site: null }) + const p = usePagination({ current: 2, last: 4 }) + assert.equal(p.href(1), '/blog?sort=new') + assert.equal(p.href(3), '/blog?sort=new&page=3') + assert.deepEqual(p.form.value, { form: 'query', param: 'page', segment: '' }) +}) + +test('the path form from the site answer with the locale segment', () => { + stub({ + fullPath: '/en/blog/page/2', + answer: { locale: 'en' }, + site: { default_locale: 'pl', pagination: { form: 'path', param: 'page', segments: { pl: 'strona', en: 'page' } } }, + }) + const p = usePagination({ current: 2, last: 3 }) + assert.equal(p.href(1), '/en/blog') + assert.equal(p.href(3), '/en/blog/page/3') + stub({ + fullPath: '/blog', + answer: null, + site: { default_locale: 'pl', pagination: { form: 'path', segments: { pl: 'strona' } } }, + }) + assert.equal(usePagination({ current: 1, last: 3 }).href(2), '/blog/strona/2') +}) + +test('the layer option without a CMS answer, with the given locale', () => { + stub({ fullPath: '/de/blog', answer: null, site: null, option: { form: 'path', segments: { de: 'seite' } } }) + const p = usePagination({ current: 1, last: 2, locale: 'de' }) + assert.equal(p.href(2), '/de/blog/seite/2') +}) + +test('prev and next head links: none on a single page, only next on the first, only prev on the last', () => { + const links = (current: number, last: number) => { + stub({ fullPath: '/blog', answer: { pagination: { form: 'query', param: 'page' } }, site: null }) + usePagination({ current, last }) + return heads[0]!().link.map((l) => `${l.rel} ${l.href}`) + } + assert.deepEqual(links(1, 1), []) + assert.deepEqual(links(1, 3), ['next /blog?page=2']) + assert.deepEqual(links(2, 3), ['prev /blog', 'next /blog?page=3']) + assert.deepEqual(links(3, 3), ['prev /blog?page=2']) + assert.deepEqual(links(5, 3), []) +}) + +test('the number of pages for %pages%: set from last, null without pages', () => { + stub({ fullPath: '/blog', answer: null, site: null }) + usePagination({ current: 1, last: 7 }) + assert.equal(useSeoPages().value, 7) + const head = seoFillPages({ title: 'Blog – strona 1 z %pages%', meta: [{ content: 'Wpisy (%pages% stron)' }, { content: 'x' }] }, useSeoPages().value as number) + assert.equal(head.title, 'Blog – strona 1 z 7') + assert.equal(head.meta[0]!.content, 'Wpisy (7 stron)') + stub({ fullPath: '/blog', answer: null, site: null }) + usePagination({ current: 1, last: 0 }) + assert.equal(useSeoPages().value, null) + assert.equal(seoFillPages({ title: '%pages%', meta: [] }, null).title, '%pages%') +}) + +test('current and last are whole numbers: current at least 1, last at least 0', () => { + stub({ fullPath: '/blog', answer: null, site: null }) + const p = usePagination({ current: 0, last: -2.5 }) + assert.equal(p.current.value, 1) + assert.equal(p.last.value, 0) + assert.equal(usePagination({ current: 2.9, last: '4' as unknown as number }).current.value, 2) +})