Files

94 lines
3.7 KiB
JavaScript

import assert from 'node:assert/strict';
import { rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { after, before, test } from 'node:test';
import { createContentStore, loadContent, parseFrontmatter, youtubeId } from '../src/content.js';
import { formatDate, localize, pickLocale } from '../src/i18n.js';
import { createFixture } from './fixtures.js';
let dir;
before(async () => {
dir = await createFixture();
});
after(() => rm(dir, { recursive: true, force: true }));
test('parseFrontmatter splits data and body', () => {
const { data, body } = parseFrontmatter('---\ntitle: Hi\n---\nBody\n');
assert.equal(data.title, 'Hi');
assert.equal(body, 'Body\n');
assert.deepEqual(parseFrontmatter('no frontmatter').data, {});
});
test('youtubeId understands the usual URL shapes', () => {
for (const url of [
'https://youtu.be/dQw4w9WgXcQ',
'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
'https://www.youtube.com/watch?feature=share&v=dQw4w9WgXcQ',
'https://www.youtube.com/shorts/dQw4w9WgXcQ',
'https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ',
]) {
assert.equal(youtubeId(url), 'dQw4w9WgXcQ', url);
}
assert.equal(youtubeId('https://vimeo.com/123'), null);
});
test('i18n helpers', () => {
assert.equal(localize({ de: 'Hallo', en: 'Hello' }, 'en'), 'Hello');
assert.equal(localize({ de: 'Nur Deutsch' }, 'en'), 'Nur Deutsch');
assert.equal(localize('plain', 'de'), 'plain');
assert.equal(pickLocale('en-US,en;q=0.9,de;q=0.8'), 'en');
assert.equal(pickLocale('fr-FR,de;q=0.5'), 'de');
assert.equal(pickLocale('fr'), 'de');
assert.equal(formatDate(2024, 'de'), '2024');
assert.equal(formatDate('2026-10', 'de'), 'Oktober 2026');
assert.equal(formatDate('2026-10-01', 'en'), 'October 2026');
});
test('drafts are hidden unless asked for', async () => {
const { content } = await loadContent(dir);
assert.deepEqual(content.projects.map((p) => p.slug), ['alpha']);
assert.equal(content.homelab, null);
assert.deepEqual(content.journey.map((e) => e.title), ['Live']);
const { content: withDrafts } = await loadContent(dir, { showDrafts: true });
assert.deepEqual(withDrafts.projects.map((p) => p.slug), ['alpha', 'beta']);
assert.ok(withDrafts.homelab);
});
test('projects: fallback language, images, video', async () => {
const { content, warnings } = await loadContent(dir, { showDrafts: true });
const alpha = content.projects.find((p) => p.slug === 'alpha');
assert.equal(alpha.text.de.title, 'Alpha');
assert.equal(alpha.text.en.title, 'Alpha');
assert.equal(alpha.text.en.fallback, 'de');
assert.equal(alpha.text.de.fallback, undefined);
assert.equal(alpha.cover.width, 1200);
assert.match(alpha.cover.srcset, /w=480&v=\w+ 480w, .*w=960.* 960w, .*w=1600.* 1200w$/);
assert.match(alpha.text.de.html, /<img src="\/media\/projects\/alpha\/cover\.png\?w=1600[^"]*" srcset=/);
assert.deepEqual(alpha.video, {
type: 'youtube',
id: 'dQw4w9WgXcQ',
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
poster: null,
});
const beta = content.projects.find((p) => p.slug === 'beta');
assert.equal(beta.text.de.fallback, 'en');
assert.ok(warnings.some((w) => w.startsWith('projects/broken/meta.yml:')), 'broken project is reported');
assert.ok(!content.projects.some((p) => p.slug === 'broken'));
});
test('a broken site.yml keeps the previous content', async () => {
const store = createContentStore({ contentDir: dir, showDrafts: false });
await store.reload();
const before = store.get();
const file = path.join(dir, 'site.yml');
await writeFile(file, 'name: [unclosed\n');
await assert.rejects(store.reload());
assert.equal(store.get(), before);
await writeFile(file, 'name: Test\n');
});