import test from 'brittle'
import { renderMarkdown, renderDiff, renderCode, renderPagination, renderBranchSelector, detectLanguage } from '../lib/render.js'
// ── Markdown ──────────────────────────────────────────────────
test('renderMarkdown — headings', (t) => {
t.ok(renderMarkdown('# Title').includes('<h1>Title</h1>'))
t.ok(renderMarkdown('## Sub').includes('<h2>Sub</h2>'))
t.ok(renderMarkdown('### Third').includes('<h3>Third</h3>'))
})
test('renderMarkdown — bold and italic', (t) => {
t.ok(renderMarkdown('**bold**').includes('<strong>bold</strong>'))
t.ok(renderMarkdown('*italic*').includes('<em>italic</em>'))
})
test('renderMarkdown — code blocks', (t) => {
const md = '```js\nconst x = 1\n```'
const html = renderMarkdown(md)
t.ok(html.includes('language-js'))
t.ok(html.includes('const x = 1'))
})
test('renderMarkdown — inline code', (t) => {
t.ok(renderMarkdown('use `npm install`').includes('<code>npm install</code>'))
})
test('renderMarkdown — links and images', (t) => {
t.ok(renderMarkdown('[link](http://x.com)').includes('<a href="http://x.com">link</a>'))
t.ok(renderMarkdown('').includes('<img src="img.png"'))
})
test('renderMarkdown — lists', (t) => {
const html = renderMarkdown('- item 1\n- item 2')
t.ok(html.includes('<li>item 1</li>'))
t.ok(html.includes('<ul>'))
})
test('renderMarkdown — empty input', (t) => {
t.is(renderMarkdown(''), '')
t.is(renderMarkdown(null), '')
})
test('renderMarkdown — escapes HTML', (t) => {
const html = renderMarkdown('<script>alert("xss")</script>')
t.absent(html.includes('<script>'))
t.ok(html.includes('<script>'))
})
// ── Diff ──────────────────────────────────────────────────────
test('renderDiff — colors additions and deletions', (t) => {
const patch = '--- a/file.js\n+++ b/file.js\n@@ -1,3 +1,3 @@\n context\n-old line\n+new line'
const html = renderDiff(patch)
t.ok(html.includes('diff-file'))
t.ok(html.includes('diff-hunk'))
t.ok(html.includes('diff-del'))
t.ok(html.includes('diff-add'))
t.ok(html.includes('diff-ctx'))
})
test('renderDiff — empty', (t) => {
t.is(renderDiff(''), '')
t.is(renderDiff(null), '')
})
// ── Code with line numbers ───────────────────────────────────
test('renderCode — line numbers', (t) => {
const html = renderCode('line 1\nline 2\nline 3')
t.ok(html.includes('data-line="1"'))
t.ok(html.includes('data-line="3"'))
t.ok(html.includes('line-num'))
t.ok(html.includes('line-code'))
t.ok(html.includes('code-table'))
})
test('renderCode — escapes HTML in code', (t) => {
const html = renderCode('<div>hello</div>')
t.ok(html.includes('<div>'))
})
test('renderCode — empty', (t) => {
t.is(renderCode(''), '')
})
// ── Pagination ───────────────────────────────────────────────
test('renderPagination — single page returns empty', (t) => {
t.is(renderPagination(10, 1, 20, '/issues'), '')
})
test('renderPagination — multiple pages', (t) => {
const html = renderPagination(100, 3, 20, '/issues')
t.ok(html.includes('page-link'))
t.ok(html.includes('page-current'))
t.ok(html.includes('Prev'))
t.ok(html.includes('Next'))
t.ok(html.includes('page=2'))
t.ok(html.includes('page=4'))
})
test('renderPagination — first page no prev', (t) => {
const html = renderPagination(100, 1, 20, '/issues')
t.absent(html.includes('Prev'))
t.ok(html.includes('Next'))
})
test('renderPagination — last page no next', (t) => {
const html = renderPagination(100, 5, 20, '/issues')
t.ok(html.includes('Prev'))
t.absent(html.includes('Next'))
})
// ── Branch selector ──────────────────────────────────────────
test('renderBranchSelector — renders options', (t) => {
const html = renderBranchSelector(['main', 'dev', 'release'], 'dev', '#/repos/foo/tree')
t.ok(html.includes('<select'))
t.ok(html.includes('branch-selector'))
t.ok(html.includes('<option value="main"'))
t.ok(html.includes('<option value="dev" selected'))
t.ok(html.includes('<option value="release"'))
})
test('renderBranchSelector — empty branches', (t) => {
t.is(renderBranchSelector([], 'main', '/'), '')
t.is(renderBranchSelector(null, 'main', '/'), '')
})
// ── Language detection ───────────────────────────────────────
test('detectLanguage — common extensions', (t) => {
t.is(detectLanguage('app.js'), 'javascript')
t.is(detectLanguage('main.py'), 'python')
t.is(detectLanguage('lib.rs'), 'rust')
t.is(detectLanguage('style.css'), 'css')
t.is(detectLanguage('data.json'), 'json')
t.is(detectLanguage('script.sh'), 'bash')
t.is(detectLanguage('player.gd'), 'gdscript')
})
test('detectLanguage — unknown', (t) => {
t.is(detectLanguage('file.xyz'), '')
t.is(detectLanguage(''), '')
})