import { describe, test, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { MarkdownUI } from './markdown-ui'
describe('MarkdownUI', () => {
test('renders plain text without markdown', () => {
render(Plain text content)
expect(screen.getByText('Plain text content')).toBeTruthy()
})
test('renders empty string', () => {
const { container } = render({''})
expect(container).toBeTruthy()
})
test('renders h1 as Typography variant h4', () => {
render(# Heading 1)
const heading = screen.getByText('Heading 1')
expect(heading.tagName).toBe('H4')
})
test('renders h2 as Typography variant h5', () => {
render(## Heading 2)
const heading = screen.getByText('Heading 2')
expect(heading.tagName).toBe('H5')
})
test('renders h3 as Typography variant h6', () => {
render(### Heading 3)
const heading = screen.getByText('Heading 3')
expect(heading.tagName).toBe('H6')
})
test('renders multiple headings of different levels', () => {
render(
{`# H1 Heading
## H2 Heading
### H3 Heading`}
,
)
expect(screen.getByText('H1 Heading')).toBeTruthy()
expect(screen.getByText('H2 Heading')).toBeTruthy()
expect(screen.getByText('H3 Heading')).toBeTruthy()
})
test('renders paragraph as Typography', () => {
render(This is a paragraph.)
expect(screen.getByText('This is a paragraph.')).toBeTruthy()
})
test('renders multiple paragraphs', () => {
render(
{`First paragraph.
Second paragraph.
Third paragraph.`}
,
)
expect(screen.getByText('First paragraph.')).toBeTruthy()
expect(screen.getByText('Second paragraph.')).toBeTruthy()
expect(screen.getByText('Third paragraph.')).toBeTruthy()
})
test('renders link with href attribute', () => {
render([Link text](https://example.com))
const link = screen.getByText('Link text')
expect(link.tagName).toBe('A')
expect(link.getAttribute('href')).toBe('https://example.com')
})
test('renders link with target="_blank" by default', () => {
render([External link](https://example.com))
const link = screen.getByText('External link')
expect(link.getAttribute('target')).toBe('_blank')
})
test('renders link with rel="noopener noreferrer" by default', () => {
render([Secure link](https://example.com))
const link = screen.getByText('Secure link')
expect(link.getAttribute('rel')).toBe('noopener noreferrer')
})
test('renders multiple links', () => {
render(
[Link 1](https://example1.com) and [Link 2](https://example2.com)
,
)
expect(screen.getByText('Link 1')).toBeTruthy()
expect(screen.getByText('Link 2')).toBeTruthy()
})
test('renders unordered list', () => {
render(
{`- Item 1
- Item 2
- Item 3`}
,
)
expect(screen.getByText('Item 1')).toBeTruthy()
expect(screen.getByText('Item 2')).toBeTruthy()
expect(screen.getByText('Item 3')).toBeTruthy()
})
test('renders ordered list', () => {
render(
{`1. First item
2. Second item
3. Third item`}
,
)
expect(screen.getByText('First item')).toBeTruthy()
expect(screen.getByText('Second item')).toBeTruthy()
expect(screen.getByText('Third item')).toBeTruthy()
})
test('renders nested lists', () => {
render(
{`- Parent 1
- Child 1
- Child 2
- Parent 2`}
,
)
expect(screen.getByText('Parent 1')).toBeTruthy()
expect(screen.getByText('Child 1')).toBeTruthy()
expect(screen.getByText('Child 2')).toBeTruthy()
expect(screen.getByText('Parent 2')).toBeTruthy()
})
test('renders list items as MUI ListItem components', () => {
render({`- List item`})
const listItem = screen.getByText('List item')
expect(listItem.classList.contains('MuiListItem-root')).toBe(true)
})
test('renders complex markdown with mixed elements', () => {
render(
{`# Main Title
This is a paragraph with [a link](https://example.com).
## Subsection
- Bullet point 1
- Bullet point 2
### Details
Another paragraph.`}
,
)
expect(screen.getByText('Main Title')).toBeTruthy()
expect(screen.getByText(/This is a paragraph/)).toBeTruthy()
expect(screen.getByText('a link')).toBeTruthy()
expect(screen.getByText('Subsection')).toBeTruthy()
expect(screen.getByText('Bullet point 1')).toBeTruthy()
expect(screen.getByText('Bullet point 2')).toBeTruthy()
expect(screen.getByText('Details')).toBeTruthy()
expect(screen.getByText('Another paragraph.')).toBeTruthy()
})
test('renders markdown with special characters', () => {
render(Text with `code` and **bold** and *italic*)
expect(screen.getByText('code')).toBeTruthy()
expect(screen.getByText('bold')).toBeTruthy()
expect(screen.getByText('italic')).toBeTruthy()
})
test('handles long markdown content', () => {
const longContent = `# Long Content
${'Paragraph. '.repeat(100)}
## Section 2
${'- Item\n'.repeat(50)}`
render({longContent})
expect(screen.getByText('Long Content')).toBeTruthy()
expect(screen.getByText('Section 2')).toBeTruthy()
})
test('renders markdown with line breaks', () => {
render(
{`Line 1
Line 2
Line 3`}
,
)
expect(screen.getByText('Line 1')).toBeTruthy()
expect(screen.getByText('Line 2')).toBeTruthy()
expect(screen.getByText('Line 3')).toBeTruthy()
})
test('renders markdown with inline code', () => {
render(Use `npm install` to install dependencies.)
expect(screen.getByText('npm install')).toBeTruthy()
expect(screen.getByText(/Use/)).toBeTruthy()
expect(screen.getByText(/to install dependencies/)).toBeTruthy()
})
test('renders markdown with emphasis', () => {
render(This is *emphasized* text)
expect(screen.getByText('emphasized')).toBeTruthy()
})
test('renders markdown with strong emphasis', () => {
render(This is **strong** text)
expect(screen.getByText('strong')).toBeTruthy()
})
test('renders only specified heading levels (h1-h3)', () => {
render(
{`# H1
## H2
### H3
#### H4
##### H5
###### H6`}
,
)
expect(screen.getByText('H1')).toBeTruthy()
expect(screen.getByText('H2')).toBeTruthy()
expect(screen.getByText('H3')).toBeTruthy()
expect(screen.getByText('H4')).toBeTruthy()
expect(screen.getByText('H5')).toBeTruthy()
expect(screen.getByText('H6')).toBeTruthy()
})
test('handles markdown with escaped characters', () => {
render(Escaped \\* asterisk and \\# hash)
expect(screen.getByText(/asterisk/)).toBeTruthy()
expect(screen.getByText(/hash/)).toBeTruthy()
})
test('renders markdown with numeric content', () => {
render(
{`1. First: 100
2. Second: 200
3. Third: 300`}
,
)
expect(screen.getByText(/First: 100/)).toBeTruthy()
expect(screen.getByText(/Second: 200/)).toBeTruthy()
expect(screen.getByText(/Third: 300/)).toBeTruthy()
})
test('preserves whitespace in code elements', () => {
render(`code with spaces`)
expect(screen.getByText(/code with.*spaces/)).toBeTruthy()
})
test('renders multiple consecutive headings', () => {
render(
{`# Heading 1
## Heading 2
### Heading 3`}
,
)
expect(screen.getByText('Heading 1').tagName).toBe('H4')
expect(screen.getByText('Heading 2').tagName).toBe('H5')
expect(screen.getByText('Heading 3').tagName).toBe('H6')
})
test('renders links within paragraphs', () => {
render(
This paragraph contains [a link](https://example.com) in the middle.
,
)
const link = screen.getByText('a link')
expect(link.tagName).toBe('A')
expect(screen.getByText(/This paragraph contains/)).toBeTruthy()
})
test('renders mixed list types', () => {
render(
{`Unordered:
- Item A
- Item B
Ordered:
1. First
2. Second`}
,
)
expect(screen.getByText('Item A')).toBeTruthy()
expect(screen.getByText('Item B')).toBeTruthy()
expect(screen.getByText('First')).toBeTruthy()
expect(screen.getByText('Second')).toBeTruthy()
})
test('renders content with all supported markdown features', () => {
render(
{`# Title
Paragraph with **bold**, *italic*, and \`code\`.
## List Section
- Item 1 with [link](https://example.com)
- Item 2
### Ordered
1. First
2. Second
End paragraph.`}
,
)
expect(screen.getByText('Title')).toBeTruthy()
expect(screen.getByText('bold')).toBeTruthy()
expect(screen.getByText('italic')).toBeTruthy()
expect(screen.getByText('code')).toBeTruthy()
expect(screen.getByText('List Section')).toBeTruthy()
expect(screen.getByText(/Item 1/)).toBeTruthy()
expect(screen.getByText('link')).toBeTruthy()
expect(screen.getByText('Item 2')).toBeTruthy()
expect(screen.getByText('Ordered')).toBeTruthy()
expect(screen.getByText('First')).toBeTruthy()
expect(screen.getByText('Second')).toBeTruthy()
expect(screen.getByText('End paragraph.')).toBeTruthy()
})
})