/** * ───────────────────────────────────────────── * SPB Git — Personal Git Platform * ───────────────────────────────────────────── * Author : Simon-Pierre Boucher * Contact : contact@spboucher.ai * File : test/unit/markdown.test.mjs * Purpose : Unit tests — the flagship README rendering pipeline * License : MIT © Simon-Pierre Boucher * ───────────────────────────────────────────── */ import { describe, it, expect, beforeAll } from 'vitest'; import { renderMarkdown, githubSlug, resolveRelativeUrl } from '../../src/render/markdown.mjs'; import { initHighlighter } from '../../src/render/highlight.mjs'; const CTX = { repo: 'demo', ref: 'main', basePath: '.', publicUrl: 'https://git.spboucher.ai' }; beforeAll(async () => { await initHighlighter(); }, 60000); describe('githubSlug', () => { it('matches the GitHub algorithm', () => { expect(githubSlug('Installation')).toBe('installation'); expect(githubSlug('Getting Started!')).toBe('getting-started'); expect(githubSlug('API — v2.0 (beta)')).toBe('api--v20-beta'); }); }); describe('resolveRelativeUrl', () => { it('rewrites relative images to raw', () => { expect(resolveRelativeUrl('./docs/demo.png', CTX, 'raw')).toBe('/raw/demo/main/docs/demo.png'); expect(resolveRelativeUrl('docs/demo.png', CTX, 'raw')).toBe('/raw/demo/main/docs/demo.png'); }); it('rewrites relative links to blob', () => { expect(resolveRelativeUrl('CONTRIBUTING.md', CTX, 'blob')).toBe('/demo/blob/main/CONTRIBUTING.md'); }); it('resolves against the document directory', () => { const nested = { ...CTX, basePath: 'docs' }; expect(resolveRelativeUrl('img/x.png', nested, 'raw')).toBe('/raw/demo/main/docs/img/x.png'); expect(resolveRelativeUrl('../top.png', nested, 'raw')).toBe('/raw/demo/main/top.png'); }); it('leaves absolute, anchor, and external URLs alone', () => { expect(resolveRelativeUrl('https://x.com/a.png', CTX, 'raw')).toBe('https://x.com/a.png'); expect(resolveRelativeUrl('#section', CTX, 'blob')).toBe('#section'); expect(resolveRelativeUrl('/already/rooted', CTX, 'blob')).toBe('/already/rooted'); }); }); describe('renderMarkdown', () => { it('keeps shields.io badges inline', async () => { const html = await renderMarkdown(' ', CTX); expect(html).toContain('src="https://img.shields.io/badge/x-y-green"'); expect(html).toContain('loading="lazy"'); }); it('renders GFM tables, strikethrough, task lists', async () => { const html = await renderMarkdown('| a |\n|---|\n| 1 |\n\n~~gone~~\n\n- [x] done\n- [ ] todo', CTX); expect(html).toContain('