// SEO values for Journal pages: description fallback, absolute og:image and // list titles. import { test } from 'node:test' import assert from 'node:assert/strict' import { absoluteUrl, htmlToText, listTitle, postSeoMeta, truncateText } from '../app/utils/seo.ts' import type { JournalPost } from '../app/utils/types.ts' function post(extra: Partial = {}): JournalPost { return { id: 1, title: 'Najnowsze Badania nad Cordycepsem', slug: 'blogbadania-nad-cordycepsem', 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, } } test('htmlToText drops tags, scripts and styles and decodes entities', () => { assert.equal( htmlToText('

A &<b> "c" 'd'

\n

e

'), 'A & "c" \'d\' e', ) assert.equal(htmlToText(null), '') }) test('truncateText keeps short text and cuts long text at a word with an ellipsis', () => { assert.equal(truncateText('krótki', 160), 'krótki') const long = 'słowo '.repeat(40).trim() const cut = truncateText(long, 160) assert.ok(cut.length <= 160) assert.ok(cut.endsWith('…')) assert.ok(!cut.endsWith(' …')) assert.equal(truncateText('x'.repeat(200), 10), `${'x'.repeat(9)}…`) }) test('the excerpt is the description when set', () => { const meta = postSeoMeta(post({ excerpt: 'Co mówi nauka.', content_html: '

Treść

' })) assert.equal(meta.description, 'Co mówi nauka.') assert.equal(meta.ogDescription, 'Co mówi nauka.') assert.equal(meta.title, 'Najnowsze Badania nad Cordycepsem') assert.equal(meta.ogTitle, meta.title) assert.equal(meta.ogType, 'article') }) test('without an excerpt the description is the first 160 characters of the body text', () => { const body = `

${'Grzyby funkcjonalne wspierają zdrowie. '.repeat(10)}

` const meta = postSeoMeta(post({ excerpt: '', content_html: body })) assert.ok(meta.description.length <= 160) assert.ok(meta.description.startsWith('Grzyby funkcjonalne wspierają zdrowie.')) assert.ok(!meta.description.includes('<')) }) test('og:image becomes absolute against the site URL', () => { const url = '/storage/app/uploads/public/665/f1e/2a3/665f1e2a3b4c5d6e7f8091.png' assert.equal(postSeoMeta(post({ featured_image_url: url }), 'https://grzybyfunkcjonalne.pl/').ogImage, `https://grzybyfunkcjonalne.pl${url}`) assert.equal(postSeoMeta(post({ featured_image_url: 'https://cdn.test/a.png' }), 'https://x.test').ogImage, 'https://cdn.test/a.png') assert.equal(postSeoMeta(post()).ogImage, undefined) }) test('article times come from published_at and updated_at', () => { const meta = postSeoMeta(post()) assert.equal(meta.articlePublishedTime, '2024-06-12T06:00:00+00:00') assert.equal(meta.articleModifiedTime, '2024-06-13T06:00:00+00:00') const bare = postSeoMeta(post({ published_at: null, updated_at: null })) assert.equal(bare.articlePublishedTime, undefined) assert.equal(bare.articleModifiedTime, undefined) }) test('absoluteUrl passes through absolute URLs and a missing site URL', () => { assert.equal(absoluteUrl('a.png', 'https://x.test'), 'https://x.test/a.png') assert.equal(absoluteUrl('HTTPS://y.test/a.png', 'https://x.test'), 'HTTPS://y.test/a.png') assert.equal(absoluteUrl('/a.png', null), '/a.png') }) test('listTitle adds the page title only after page 1', () => { assert.equal(listTitle('Artykuły', 1, 'Strona 1'), 'Artykuły') assert.equal(listTitle('Artykuły', 2, 'Strona 2'), 'Artykuły · Strona 2') })