import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import MarkdownContent from './MarkdownContent';
import rehypeExternalLinks from '../__mocks__/rehype-external-links';
const BOLD_TEXT = '**Bold text**';
const ITALIC_TEXT = '*Italic text*';
const INLINE_CODE = 'Here is inline code: `const x = 5`';
const CODE_BLOCK = `\`\`\`javascript
function hello() {
console.log('Hello, world!');
}
\`\`\``;
const HEADING = '# Heading 1';
const LINK = '[PatternFly](https://www.patternfly.org/)';
const UNORDERED_LIST = `
* Item 1
* Item 2
* Item 3
`;
const ORDERED_LIST = `
1. First item
2. Second item
3. Third item
`;
const TABLE = `
| Column 1 | Column 2 |
|----------|----------|
| Cell 1 | Cell 2 |
| Cell 3 | Cell 4 |
`;
const BLOCKQUOTE = '> This is a blockquote';
const IMAGE = '';
describe('MarkdownContent', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should render bold text correctly', () => {
const { container } = render();
expect(container.querySelector('strong')).toBeTruthy();
expect(screen.getByText('Bold text')).toBeTruthy();
});
it('should render italic text correctly', () => {
const { container } = render();
expect(container.querySelector('em')).toBeTruthy();
expect(screen.getByText('Italic text')).toBeTruthy();
});
it('should render inline code correctly', () => {
render();
expect(screen.getByText(/const x = 5/)).toBeTruthy();
});
it('should render code blocks correctly', () => {
render();
expect(screen.getByText(/function hello/)).toBeVisible();
expect(screen.getByText(/console.log/)).toBeVisible();
expect(screen.getByRole('button', { name: 'Copy code' })).toBeVisible();
});
it('should render headings correctly', () => {
render();
expect(screen.getByRole('heading', { name: /Heading 1/i })).toBeTruthy();
});
it('should render links correctly', () => {
render();
expect(screen.getByRole('link', { name: /PatternFly/i })).toBeTruthy();
});
it('should render unordered lists correctly', () => {
render();
expect(screen.getByText('Item 1')).toBeTruthy();
expect(screen.getByText('Item 2')).toBeTruthy();
expect(screen.getByText('Item 3')).toBeTruthy();
expect(screen.getAllByRole('listitem')).toHaveLength(3);
});
it('should render ordered lists correctly', () => {
render();
expect(screen.getByText('First item')).toBeTruthy();
expect(screen.getByText('Second item')).toBeTruthy();
expect(screen.getByText('Third item')).toBeTruthy();
expect(screen.getAllByRole('listitem')).toHaveLength(3);
});
it('should render tables correctly', () => {
render();
expect(screen.getByRole('grid', { name: /Test table/i })).toBeTruthy();
expect(screen.getByRole('columnheader', { name: /Column 1/i })).toBeTruthy();
expect(screen.getByRole('columnheader', { name: /Column 2/i })).toBeTruthy();
expect(screen.getByRole('cell', { name: /Cell 1/i })).toBeTruthy();
expect(screen.getByRole('cell', { name: /Cell 2/i })).toBeTruthy();
});
it('should render blockquotes correctly', () => {
render();
const quote = screen.getByText(/This is a blockquote/);
expect(quote).toBeVisible();
expect(quote.closest('.pf-v6-c-content--blockquote')?.tagName).toBe('BLOCKQUOTE');
});
it('should render images when hasNoImages is false', () => {
render();
expect(screen.getByRole('img', { name: /Alt text/i })).toBeTruthy();
});
it('should not render images when hasNoImages is true', () => {
render();
expect(screen.queryByRole('img', { name: /Alt text/i })).toBeFalsy();
});
it('should disable markdown rendering when isMarkdownDisabled is true', () => {
render();
expect(screen.getByText('**Bold text**')).toBeTruthy();
});
it('should render text component when isMarkdownDisabled is true and textComponent is provided', () => {
const textComponent =
Custom text component
;
render();
expect(screen.getByTestId('custom-text')).toBeTruthy();
expect(screen.getByText('Custom text component')).toBeTruthy();
});
it('should apply isPrimary prop to elements', () => {
const { container } = render();
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
});
it('should apply shouldRetainStyles prop to elements', () => {
const { container } = render();
expect(container.querySelector('.pf-m-markdown')).toBeTruthy();
});
it('should pass codeBlockProps to code blocks', () => {
render();
expect(screen.getByRole('button', { name: /Custom code block/i })).toBeTruthy();
});
it('should pass tableProps to tables', () => {
render();
expect(screen.getByRole('grid', { name: /Custom table label/i })).toBeTruthy();
});
it('should open links in new tab when openLinkInNewTab is true', () => {
render();
expect(rehypeExternalLinks).toHaveBeenCalledTimes(1);
});
it('should not open links in new tab when openLinkInNewTab is false', () => {
render();
expect(rehypeExternalLinks).not.toHaveBeenCalled();
});
it('should pass linkProps to links', async () => {
const onClick = jest.fn();
render();
const link = screen.getByRole('link', { name: /PatternFly/i });
link.click();
expect(onClick).toHaveBeenCalledTimes(1);
});
it('should handle reactMarkdownProps.disallowedElements', () => {
render();
// Code block should not render when disallowed
expect(screen.queryByRole('button', { name: /Copy code/i })).toBeFalsy();
});
it('should render plain text when no markdown is present', () => {
render();
expect(screen.getByText('Plain text without markdown')).toBeTruthy();
});
it('should handle empty content', () => {
const { container } = render();
expect(container.textContent).toBe('');
});
it('should handle undefined content', () => {
const { container } = render();
expect(container.textContent).toBe('');
});
it('should render multiple markdown elements together', () => {
const content = `# Heading
**Bold text** and *italic text*
\`\`\`javascript
const x = 5;
\`\`\`
[Link](https://example.com)`;
render();
expect(screen.getByRole('heading', { name: /Heading/i })).toBeTruthy();
expect(screen.getByText('Bold text')).toBeTruthy();
expect(screen.getByText('italic text')).toBeTruthy();
expect(screen.getByText(/const x = 5/)).toBeTruthy();
expect(screen.getByRole('link', { name: /Link/i })).toBeTruthy();
});
});