Files

24 lines
1.9 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import {readArticles,articleUrl,home,articlePage} from '../scripts/site.mjs';
async function fixture(t, files) {
const dir=await fs.mkdtemp(path.join(os.tmpdir(),'truenews-'));
t.after(()=>fs.rm(dir,{recursive:true,force:true}));
for(const [name,text] of Object.entries(files)) await fs.writeFile(path.join(dir,name),text);
return dir;
}
test('Markdown supports metadata, nested URLs, fallback titles, and safe HTML', async t=>{
const dir=await fixture(t,{'first.md':'---\ntitle: "First <story>"\nurl: /world/first\ndate: 2026-09-12\n---\n## Context\n\n**Strong** text\n\n<script>alert(1)</script>\n\n[bad](javascript:alert)\n','second.md':'# Second story\n\nA paragraph.','ignored.txt':'not an article'});
const articles=await readArticles(dir);
assert.equal(articles.length,2);assert.equal(articles[0].url,'/world/first/');
assert.match(articles[0].html,/<strong>Strong<\/strong>/);assert.doesNotMatch(articles[0].html,/<script|javascript:/);
assert.equal(articles[1].title,'Second story');assert.equal(articles[1].url,'/second/');
assert.match(home(articles),/First &lt;story&gt;/);assert.match(articlePage(articles[0],articles),/Context/);
});
test('rejects unsafe and reserved paths',()=>{for(const url of ['../oops','/assets/x','/404','https://example.com','/a?x=1','/'])assert.throws(()=>articleUrl(url));assert.equal(articleUrl('hello-world'),'/hello-world/');});
test('duplicate URLs fail visibly',async t=>{const dir=await fixture(t,{'a.md':'---\nurl: /same\n---\na','b.md':'---\nurl: /same/\n---\nb'});await assert.rejects(readArticles(dir),/Duplicate/);});
test('empty pages directory renders a useful home page',async t=>{assert.match(home(await readArticles(await fixture(t,{}))),/Your next story starts here/);});