import { ribbit } from './setup'; const r = ribbit(); const hopdown = new r.HopDown(); const H = (md: string) => hopdown.toHTML(md); const M = (html: string) => hopdown.toMarkdown(html); const rt = (md: string) => M(H(md)); describe('Markdown → HTML', () => { describe('inline formatting', () => { it('bold', () => expect(H('**bold**')).toBe('
bold
')); it('italic', () => expect(H('*italic*')).toBe('italic
')); it('inline code', () => expect(H('`code`')).toBe('code
bi
')); it('mixed', () => expect(H('a **b** *c* `d`')).toBe('a b c d
a b
')); it('content', () => expect(H('> hello')).toContain('hello')); it('multi-line', () => expect(H('> a\n> b')).toContain('a')); }); describe('fenced code', () => { it('basic', () => expect(H('```\nx = 1\n```')).toContain('')); it('content', () => expect(H('```\nx = 1\n```')).toContain('x = 1')); it('language', () => expect(H('```js\nvar x;\n```')).toContain('language-js')); it('escapes html', () => expect(H('```\n\n```')).toContain('<div>')); it('no lang when none', () => expect(H('```\nplain\n```')).not.toContain('language-')); }); describe('tables', () => { const tbl = '| a | b |\n|---|---|\n| 1 | 2 |'; it('table tag', () => expect(H(tbl)).toContain('')); it('thead', () => expect(H(tbl)).toContain('')); it('th cells', () => expect(H(tbl)).toContain('
a ')); it('td cells', () => expect(H(tbl)).toContain('1 ')); it('center align', () => expect(H('| C |\n|:--:|\n| x |')).toContain('text-align:center')); it('right align', () => expect(H('| R |\n|--:|\n| x |')).toContain('text-align:right')); it('inline md', () => expect(H('| **b** |\n|---|\n| x |')).toContain('b')); }); describe('paragraphs', () => { it('single', () => expect(H('hello')).toBe('hello
')); it('two', () => expect(H('a\n\nb')).toBe('a
\nb
')); it('soft break', () => expect(H('a\nb')).toBe('a\nb
')); }); describe('edge cases', () => { it('empty', () => expect(H('')).toBe('')); it('whitespace', () => expect(H(' ')).toBe('')); it('html entities', () => expect(H('a & b < c')).toContain('&')); it('html in code', () => expect(H('``')).toContain('<div>')); it('para then heading', () => expect(H('text\n\n## H')).toContain('expect(H('- a\n\ntext')).toContain('
text
')); }); }); describe('HTML → Markdown', () => { it('strong→**', () => expect(M('b
')).toBe('**b**')); it('em→*', () => expect(M('i
')).toBe('*i*')); it('code→`', () => expect(M('')).toBe('`c`')); it('a→[]', () => expect(M('t')).toBe('[t](http://x)')); it('h1→#', () => expect(M('
cT
')).toBe('# T')); it('hr→---', () => expect(M('
')).toBe('---')); it('ul→-', () => expect(M('')).toBe('- a\n- b')); it('ol→1.', () => expect(M('
- a
- b
')).toBe('1. a\n2. b')); it('bq→>', () => expect(M('
- a
- b
')).toContain('> ')); it('pre→```', () => expect(M('q
')).toContain('```')); it('pre lang', () => expect(M('x')).toContain('```py')); it('table→pipes', () => { const html = 'x'; expect(M(html)).toContain('| a | b |'); }); }); describe('Round-trips', () => { it.each([ ['paragraph', 'Hello world'], ['bold', '**bold**'], ['italic', '*italic*'], ['code', '`code`'], ['link', '[t](http://x)'], ['h1', '# Title'], ['h2', '## Sub'], ['ul', '- a\n- b'], ['ol', '1. a\n2. b'], ])('%s', (_, md) => expect(rt(md)).toBe(md)); it('hr', () => expect(rt('---')).toBe('---')); it('blockquote', () => expect(rt('> quoted')).toContain('> ')); it('code block', () => expect(rt('```\nx = 1\n```')).toContain('```')); it('table', () => expect(rt('| a | b |\n|---|---|\n| 1 | 2 |')).toContain('| a | b |')); }); describe('Nested inline', () => { it('bold wraps italic', () => expect(H('**a *b* c**')).toBe('
a b 1 2 a b c
')); it('italic wraps bold', () => expect(H('*a **b** c*')).toBe('a b c
')); it('bold wraps code', () => expect(H('**a `b` c**')).toBe('a
')); it('bold wraps link', () => expect(H('**[t](u)**')).toBe('')); it('link with bold', () => expect(H('[**t**](u)')).toBe('')); it('link with code', () => expect(H('[`t`](u)')).toBe('')); }); describe('Nested blocks', () => { it('bq > heading', () => expect(H('> # Title')).toContain('bclist', () => expect(H('> - a\n> - b')).toContain('
')); it('bq > bq', () => expect(H('> > nested')).toContain('
')); it('li > bold', () => expect(H('- **bold**')).toContain('bold')); it('heading > code', () => expect(H('## `code`')).toContain('code')); it('table > bold', () => expect(H('| **b** |\n|---|\n| x |')).toContain('b')); }); describe('Nested lists', () => { it('ul > ul', () => expect(H('- a\n - b\n - c\n- d')).toBe('')); it('ol > ol', () => expect(H('1. a\n 1. b\n 1. c\n2. d')).toBe('
- a
- b
- c
- d
')); it('ul > ol', () => expect(H('- a\n 1. b\n 2. c\n- d')).toBe('
- a
- b
- c
- d
')); it('3-level', () => expect(H('- a\n - b\n - c\n- d')).toBe('
- a
- b
- c
- d
')); it('ul>ul rt', () => expect(rt('- a\n - b\n - c\n- d')).toBe('- a\n - b\n - c\n- d')); }); describe('Tables with nested markdown', () => { it('td bold', () => expect(H('| h |\n|---|\n| **b** |')).toContain('
- a
- b
- c
- d
b ')); it('td link>bold', () => expect(H('| h |\n|---|\n| [**t**](u) |')).toContain('t')); it('td bold rt', () => expect(rt('| h |\n|---|\n| **b** |')).toBe('| h |\n| --- |\n| **b** |')); it('multi-cell rt', () => expect(rt('| **a** | *b* |\n|---|---|\n| `c` | [d](e) |')).toBe('| **a** | *b* |\n| --- | --- |\n| `c` | [d](e) |')); });