import { describe, test } from 'node:test'; import assert from 'node:assert/strict'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { markdownToHtml, inline } from '../build-html.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe('markdownToHtml — tables (beslutning H)', () => { test('converts a pipe table to //
', () => { const md = [ '| Plattform | Pris |', '| --- | --- |', '| Azure | Høy |', '| Foundry | Lav |', ].join('\n'); const html = markdownToHtml(md); assert.match(html, //); assert.match(html, //); assert.match(html, /
/); // header cells render as , body values as assert.match(html, /Plattform<\/th>/); assert.match(html, /Azure<\/td>/); // the separator row must NOT become a data row assert.doesNotMatch(html, /---<\/td>/); }); test('empty input produces no table', () => { assert.doesNotMatch(markdownToHtml(''), //); }); test('tolerates a malformed row (uneven cell count) without throwing', () => { const md = [ '| a | b |', '| --- | --- |', '| only-one-cell |', '| x | y |', ].join('\n'); let html; assert.doesNotThrow(() => { html = markdownToHtml(md); }); assert.match(html, /
/); assert.match(html, /
x<\/td>/); }); }); describe('markdownToHtml — heading levels # … #### (beslutning H)', () => { test('# renders

', () => { assert.match(markdownToHtml('# Tittel'), /

Tittel<\/h1>/); }); test('## renders

', () => { assert.match(markdownToHtml('## Seksjon'), /

Seksjon<\/h2>/); }); test('### renders

', () => { assert.match(markdownToHtml('### Under'), /

Under<\/h3>/); }); test('#### renders

', () => { assert.match(markdownToHtml('#### Detalj'), /

Detalj<\/h4>/); }); }); describe('inline — backtick code span (beslutning H)', () => { test('`code` renders ', () => { assert.match(inline('bruk `npm install` her'), /npm install<\/code>/); }); test('still handles **bold** and *italic*', () => { assert.match(inline('**fet** og *kursiv*'), /fet<\/strong>/); assert.match(inline('**fet** og *kursiv*'), /kursiv<\/em>/); }); }); // Paritetstilfeller portet fra maskinrommets tools/__tests__/build-html.test.mjs // (N3.5/MR-F8): lenker, flerlinjers blockquote, FIGUR→SVG. Samme markdown skal // gi samme parser-HTML i begge motorer. describe('inline — lenker [tekst](url) (N3.5 MR-F8)', () => { test('renders [tekst](url) as a link with target/rel', () => { const out = inline('se [Reuters](https://www.reuters.com/x) for detaljer'); assert.match(out, /]*>Reuters<\/a>/); assert.match(out, /target="_blank"/); assert.match(out, /rel="noopener"/); }); test('mailto is allowed', () => { assert.match(inline('[skriv](mailto:x@y.no)'), / { const out = inline('[klikk](javascript:alert(1))'); assert.doesNotMatch(out, / { test('a blockquote keeps its paragraph breaks', () => { const md = ['> Første avsnitt.', '>', '> Andre avsnitt.'].join('\n'); const html = markdownToHtml(md); assert.match(html, /
/); // two separate

inside the quote — the old parser collapsed these into one const paras = html.match(/

(.*?)<\/blockquote>/s)[1].match(/

/g) || []; assert.equal(paras.length, 2); }); test('a single-paragraph blockquote still renders one

', () => { const html = markdownToHtml('> Bare ett avsnitt her.'); const paras = html.match(/

(.*?)<\/blockquote>/s)[1].match(/

/g) || []; assert.equal(paras.length, 1); }); }); describe('markdownToHtml — FIGUR→SVG (N3.5 MR-F8)', () => { test('a FIGUR blockquote with no matching SVG falls back to a plain blockquote', () => { const html = markdownToHtml('> **[FIGUR 9 — «finnes ikke»]**'); assert.match(html, /

/); assert.doesNotMatch(html, /
', () => { const prev = process.cwd(); process.chdir(path.join(__dirname, 'fixtures', 'figur-serie')); try { const html = markdownToHtml('> **[FIGUR 1 — «Demo-figur»]**'); assert.match(html, /
/); assert.match(html, /Figur 1 — Demo-figur<\/figcaption>/); // xml-deklarasjonen i SVG-fila skal strippes før inlining assert.doesNotMatch(html, /<\?xml/); assert.doesNotMatch(html, /
/); } finally { process.chdir(prev); } }); });