Barazo default frontend barazo.forum
at main 94 lines 3.3 kB view raw
1/** 2 * Tests for MarkdownContent component. 3 */ 4 5import { describe, it, expect } from 'vitest' 6import { render, screen } from '@testing-library/react' 7import { axe } from 'vitest-axe' 8import { MarkdownContent } from './markdown-content' 9 10describe('MarkdownContent', () => { 11 it('renders plain text', () => { 12 render(<MarkdownContent content="Hello world" />) 13 expect(screen.getByText('Hello world')).toBeInTheDocument() 14 }) 15 16 it('renders bold text', () => { 17 const { container } = render(<MarkdownContent content="This is **bold** text" />) 18 const strong = container.querySelector('strong') 19 expect(strong).toBeInTheDocument() 20 expect(strong).toHaveTextContent('bold') 21 }) 22 23 it('renders italic text', () => { 24 const { container } = render(<MarkdownContent content="This is *italic* text" />) 25 const em = container.querySelector('em') 26 expect(em).toBeInTheDocument() 27 expect(em).toHaveTextContent('italic') 28 }) 29 30 it('renders links with target and rel attributes', () => { 31 render(<MarkdownContent content="Visit [Example](https://example.com)" />) 32 const link = screen.getByRole('link', { name: 'Example' }) 33 expect(link).toHaveAttribute('href', 'https://example.com') 34 expect(link).toHaveAttribute('rel', expect.stringContaining('noopener')) 35 }) 36 37 it('renders code blocks', () => { 38 const { container } = render(<MarkdownContent content={'```\nconst x = 1;\n```'} />) 39 const code = container.querySelector('code') 40 expect(code).toBeInTheDocument() 41 expect(code).toHaveTextContent('const x = 1;') 42 }) 43 44 it('renders inline code', () => { 45 const { container } = render(<MarkdownContent content="Use `npm install` to install" />) 46 const code = container.querySelector('code') 47 expect(code).toBeInTheDocument() 48 expect(code).toHaveTextContent('npm install') 49 }) 50 51 it('renders unordered lists', () => { 52 const { container } = render(<MarkdownContent content={'- Item 1\n- Item 2\n- Item 3'} />) 53 const list = container.querySelector('ul') 54 expect(list).toBeInTheDocument() 55 const items = container.querySelectorAll('li') 56 expect(items.length).toBe(3) 57 }) 58 59 it('strips dangerous HTML (XSS prevention)', () => { 60 const { container } = render( 61 <MarkdownContent content='<script>alert("xss")</script><p>Safe content</p>' /> 62 ) 63 expect(container.querySelector('script')).not.toBeInTheDocument() 64 expect(screen.getByText('Safe content')).toBeInTheDocument() 65 }) 66 67 it('strips event handler attributes', () => { 68 const { container } = render( 69 <MarkdownContent content='<img src="x" onerror="alert(1)"><p>Safe</p>' /> 70 ) 71 const img = container.querySelector('img') 72 if (img) { 73 expect(img.getAttribute('onerror')).toBeNull() 74 } 75 }) 76 77 it('applies prose styling class', () => { 78 const { container } = render(<MarkdownContent content="Hello" />) 79 const wrapper = container.firstChild as HTMLElement 80 expect(wrapper.className).toContain('prose') 81 }) 82 83 it('passes axe accessibility check', async () => { 84 const { container } = render( 85 <MarkdownContent 86 content={ 87 '## Heading\n\nA paragraph with **bold** and a [link](https://example.com).\n\n- Item 1\n- Item 2' 88 } 89 /> 90 ) 91 const results = await axe(container) 92 expect(results).toHaveNoViolations() 93 }) 94})