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() }) })