Download packages/cli/src/ui/utils/MarkdownDisplay.test.tsx from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 6.73 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/utils/MarkdownDisplay.test.tsx
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/ui/utils/MarkdownDisplay.test.tsx
-
curl -L -o MarkdownDisplay.test.tsx https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/utils/MarkdownDisplay.test.tsx
6.73 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { describe, it, expect, vi, beforeEach } from 'vitest'; | |
| import { MarkdownDisplay } from './MarkdownDisplay.js'; | |
| import { LoadedSettings } from '../../config/settings.js'; | |
| import { renderWithProviders } from '../../test-utils/render.js'; | |
| describe('<MarkdownDisplay />', () => { | |
| const baseProps = { | |
| isPending: false, | |
| terminalWidth: 80, | |
| availableTerminalHeight: 40, | |
| }; | |
| beforeEach(() => { | |
| vi.clearAllMocks(); | |
| }); | |
| it('renders nothing for empty text', async () => { | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text="" />, | |
| ); | |
| expect(lastFrame({ allowEmpty: true })).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders a simple paragraph', async () => { | |
| const text = 'Hello, world.'; | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| const lineEndings = [ | |
| { name: 'Windows', eol: '\r\n' }, | |
| { name: 'Unix', eol: '\n' }, | |
| ]; | |
| describe.each(lineEndings)('with $name line endings', ({ eol }) => { | |
| it('renders headers with correct levels', async () => { | |
| const text = ` | |
| # Header 1 | |
| ## Header 2 | |
| ### Header 3 | |
| #### Header 4 | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders a fenced code block with a language', async () => { | |
| const text = '```javascript\nconst x = 1;\nconsole.log(x);\n```'.replace( | |
| /\n/g, | |
| eol, | |
| ); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders a fenced code block without a language', async () => { | |
| const text = '```\nplain text\n```'.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('handles unclosed (pending) code blocks', async () => { | |
| const text = '```typescript\nlet y = 2;'.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} isPending={true} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders unordered lists with different markers', async () => { | |
| const text = ` | |
| - item A | |
| * item B | |
| + item C | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders nested unordered lists', async () => { | |
| const text = ` | |
| * Level 1 | |
| * Level 2 | |
| * Level 3 | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders ordered lists', async () => { | |
| const text = ` | |
| 1. First item | |
| 2. Second item | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders horizontal rules', async () => { | |
| const text = ` | |
| Hello | |
| --- | |
| World | |
| *** | |
| Test | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('renders tables correctly', async () => { | |
| const text = ` | |
| | Header 1 | Header 2 | | |
| |----------|:--------:| | |
| | Cell 1 | Cell 2 | | |
| | Cell 3 | Cell 4 | | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('handles a table at the end of the input', async () => { | |
| const text = ` | |
| Some text before. | |
| | A | B | | |
| |---| | |
| | 1 | 2 |`.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('inserts a single space between paragraphs', async () => { | |
| const text = `Paragraph 1. | |
| Paragraph 2.`.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('correctly parses a mix of markdown elements', async () => { | |
| const text = ` | |
| # Main Title | |
| Here is a paragraph. | |
| - List item 1 | |
| - List item 2 | |
| \`\`\` | |
| some code | |
| \`\`\` | |
| Another paragraph. | |
| `.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| unmount(); | |
| }); | |
| it('hides line numbers in code blocks when showLineNumbers is false', async () => { | |
| const text = '```javascript\nconst x = 1;\n```'.replace(/\n/g, eol); | |
| const settings = new LoadedSettings( | |
| { path: '', settings: {}, originalSettings: {} }, | |
| { path: '', settings: {}, originalSettings: {} }, | |
| { | |
| path: '', | |
| settings: { ui: { showLineNumbers: false } }, | |
| originalSettings: { ui: { showLineNumbers: false } }, | |
| }, | |
| { path: '', settings: {}, originalSettings: {} }, | |
| true, | |
| [], | |
| ); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| { settings }, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| expect(lastFrame()).not.toContain('1 const x = 1;'); | |
| unmount(); | |
| }); | |
| it('shows line numbers in code blocks by default', async () => { | |
| const text = '```javascript\nconst x = 1;\n```'.replace(/\n/g, eol); | |
| const { lastFrame, unmount } = await renderWithProviders( | |
| <MarkdownDisplay {...baseProps} text={text} />, | |
| ); | |
| expect(lastFrame()).toMatchSnapshot(); | |
| expect(lastFrame()).toContain('1 const x = 1;'); | |
| unmount(); | |
| }); | |
| }); | |
| }); | |