import { describe, it, expect } from 'vitest' import { renderMarkdown, renderMarkdownSync } from '../markdown' describe('renderMarkdown (MetonaEditor 内置解析器)', () => { it('should render a simple heading', async () => { const result = await renderMarkdown('# Hello World') expect(result).toContain(' { const result = await renderMarkdown('**bold**') expect(result).toContain(' { const result = await renderMarkdown('*italic*') expect(result).toContain(' { const result = await renderMarkdown('`code`') expect(result).toContain(' { const md = '```javascript\nconst x = 1;\n```' const result = await renderMarkdown(md) expect(result).toContain(' { const result = await renderMarkdown('[link](https://example.com)') expect(result).toContain(' { const result = await renderMarkdown('- item 1\n- item 2') expect(result).toContain(' { const result = await renderMarkdown('1. first\n2. second') expect(result).toContain(' { const result = await renderMarkdown('> quote') expect(result).toContain(' { const md = '| A | B |\n|---|---|\n| 1 | 2 |' const result = await renderMarkdown(md) expect(result).toContain(' { const result = await renderMarkdown('~~deleted~~') expect(result).toContain(' { const result = await renderMarkdown('- [x] done\n- [ ] todo') expect(result).toContain('me-task-item') expect(result).toContain('checked') }) it('should render mermaid as .me-mermaid container', async () => { const md = '```mermaid\ngraph TD\nA-->B\n```' const result = await renderMarkdown(md) expect(result).toContain('me-mermaid') expect(result).toContain('class="mermaid"') expect(result).toContain('graph TD') }) it('should handle empty content', async () => { const result = await renderMarkdown('') expect(result).toBe('') }) it('should handle null and undefined filePath', async () => { expect(await renderMarkdown('# No File', null)).toContain('No File') expect(await renderMarkdown('# No File')).toContain('No File') }) it('should be sync-callable via renderMarkdownSync', () => { const result = renderMarkdownSync('# Sync') expect(result).toContain(' { const FILE = '/home/user/docs/note.md' it('should fix relative image paths to file://', async () => { const result = await renderMarkdown('![img](./pic.png)', FILE) expect(result).toContain('src="file:///home/user/docs/pic.png"') }) it('should fix nested relative paths', async () => { const result = await renderMarkdown('![img](assets/a.png)', FILE) expect(result).toContain('src="file:///home/user/docs/assets/a.png"') }) it('should fix unix absolute paths', async () => { const result = await renderMarkdown('![img](/abs/pic.png)', FILE) expect(result).toContain('src="file:///abs/pic.png"') }) it('should not touch http/https/data:/file: URLs', async () => { const md = '![a](https://x.com/a.png) ![b](data:image/png;base64,xx) ![c](file:///c.png)' const result = await renderMarkdown(md, FILE) expect(result).toContain('https://x.com/a.png') expect(result).toContain('data:image/png;base64,xx') expect(result).toContain('file:///c.png') }) it('should skip out-of-directory traversal (../ and ../../)', async () => { const md = '![a](../outside.png) ![b](../../outside.png)' const result = await renderMarkdown(md, FILE) // 越界路径保持原样(不注入 file://) expect(result).not.toContain('file:') expect(result).toContain('../outside.png') expect(result).toContain('../../outside.png') }) it('should not treat sibling directory with same prefix as inside', async () => { // /home/user/docs-other/ 与 /home/user/docs/ 前缀相似但目录不同 const result = await renderMarkdown('![img](../docs-other/pic.png)', FILE) expect(result).not.toContain('file:') expect(result).toContain('../docs-other/pic.png') }) it('should not touch images when filePath is null', async () => { const result = await renderMarkdown('![img](./pic.png)') expect(result).toContain('./pic.png') expect(result).not.toContain('file:') }) it('should fix relative image paths from root-level file', async () => { const result = await renderMarkdown('![img](./pic.png)', '/note.md') expect(result).toContain('src="file:///pic.png"') }) it('should escape special chars in fixed path', async () => { const result = await renderMarkdown('![img](./a&b.png)', FILE) expect(result).toContain('src="file:///home/user/docs/a&b.png"') }) }) describe('XSS 防护(内置 safeUrl)', () => { it('should not emit anchor for javascript: URLs', async () => { const result = await renderMarkdown('[x](javascript:alert(1))') // 内置解析器将危险 URL 转义原样输出(不生成 ),文本不构成可执行链接 expect(result).not.toContain(' { const result = await renderMarkdown('![x](javascript:alert(1))') expect(result).not.toContain('