- node --test over routes, client (fake fetcher, include_empty=1), pagination, htmlGate (Go FormatHTML parity cases), sitemap, seo and pl/en i18n parity - package script test and a Testing line in the README
99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
// Sitemap entries are built from journal.routes, never from fixed paths.
|
|
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { buildJournalSitemapEntries } from '../app/utils/sitemap.ts'
|
|
import { DEFAULT_JOURNAL_ROUTES, normalizeJournalRoutes } from '../app/utils/routes.ts'
|
|
import type { JournalCategory, JournalPost } from '../app/utils/types.ts'
|
|
|
|
function post(id: number, slug: string, extra: Partial<JournalPost> = {}): JournalPost {
|
|
return {
|
|
id,
|
|
title: slug,
|
|
slug,
|
|
excerpt: null,
|
|
content: null,
|
|
content_html: null,
|
|
reading_time: 1,
|
|
published: true,
|
|
published_at: '2024-06-12T06:00:00+00:00',
|
|
is_pinned: false,
|
|
metadata: null,
|
|
sources: null,
|
|
author: null,
|
|
categories: [],
|
|
tags: [],
|
|
featured_images: [],
|
|
featured_image_url: null,
|
|
translations: null,
|
|
created_at: '2024-06-12T06:00:00+00:00',
|
|
updated_at: '2024-06-13T06:00:00+00:00',
|
|
...extra,
|
|
}
|
|
}
|
|
|
|
function category(id: number, slug: string, children?: JournalCategory[]): JournalCategory {
|
|
const row: JournalCategory = {
|
|
id,
|
|
name: slug,
|
|
slug,
|
|
description: null,
|
|
content: null,
|
|
parent_id: null,
|
|
nest_depth: 0,
|
|
post_count: 0,
|
|
}
|
|
if (children) row.children = children
|
|
return row
|
|
}
|
|
|
|
const POSTS = [post(1, 'blogbadania-nad-cordycepsem'), post(2, 'bez-daty', { updated_at: null })]
|
|
const CATEGORIES = [category(1, 'cordyceps', [category(2, 'militaris')]), category(3, 'amanita-muscaria')]
|
|
|
|
test('default routes give /blog/:slug and /blog/category/:category', () => {
|
|
assert.deepEqual(buildJournalSitemapEntries(POSTS, CATEGORIES, { ...DEFAULT_JOURNAL_ROUTES }), [
|
|
{ loc: '/blog/blogbadania-nad-cordycepsem', lastmod: '2024-06-13T06:00:00+00:00' },
|
|
{ loc: '/blog/bez-daty' },
|
|
{ loc: '/blog/category/cordyceps' },
|
|
{ loc: '/blog/category/militaris' },
|
|
{ loc: '/blog/category/amanita-muscaria' },
|
|
])
|
|
})
|
|
|
|
test('a custom root category route gives /cordyceps', () => {
|
|
const routes = normalizeJournalRoutes({ category: '/:category', tag: false })
|
|
const locs = buildJournalSitemapEntries(POSTS, CATEGORIES, routes).map((e) => e.loc)
|
|
assert.ok(locs.includes('/cordyceps'))
|
|
assert.ok(locs.includes('/militaris'), 'nested categories are flattened')
|
|
assert.ok(locs.includes('/amanita-muscaria'), 'empty categories are listed')
|
|
})
|
|
|
|
test('a disabled route contributes nothing', () => {
|
|
const noCategories = normalizeJournalRoutes({ category: false })
|
|
assert.deepEqual(
|
|
buildJournalSitemapEntries(POSTS, CATEGORIES, noCategories).map((e) => e.loc),
|
|
['/blog/blogbadania-nad-cordycepsem', '/blog/bez-daty'],
|
|
)
|
|
const noPosts = normalizeJournalRoutes({ post: false })
|
|
assert.equal(buildJournalSitemapEntries(POSTS, CATEGORIES, noPosts).filter((e) => e.loc.startsWith('/blog/b')).length, 0)
|
|
})
|
|
|
|
test('unpublished posts and empty slugs are skipped', () => {
|
|
const rows = [post(1, 'draft', { published: false }), post(2, ''), post(3, 'live')]
|
|
assert.deepEqual(
|
|
buildJournalSitemapEntries(rows, [category(9, '')], { ...DEFAULT_JOURNAL_ROUTES }).map((e) => e.loc),
|
|
['/blog/live'],
|
|
)
|
|
})
|
|
|
|
test('lastmod comes from updated_at', () => {
|
|
const [entry] = buildJournalSitemapEntries([post(1, 'x', { updated_at: '2025-01-02T03:04:05+00:00' })], [], {
|
|
...DEFAULT_JOURNAL_ROUTES,
|
|
})
|
|
assert.equal(entry?.lastmod, '2025-01-02T03:04:05+00:00')
|
|
})
|
|
|
|
test('slugs are encoded per segment', () => {
|
|
const [entry] = buildJournalSitemapEntries([post(1, 'a b/c')], [], { ...DEFAULT_JOURNAL_ROUTES })
|
|
assert.equal(entry?.loc, '/blog/a%20b/c')
|
|
})
|