mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
247 lines
6.4 KiB
TypeScript
247 lines
6.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { render } from 'ink-testing-library';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { MarkdownDisplay } from './MarkdownDisplay.js';
|
|
import { LoadedSettings } from '../../config/settings.js';
|
|
import { SettingsContext } from '../contexts/SettingsContext.js';
|
|
|
|
describe('<MarkdownDisplay />', () => {
|
|
const baseProps = {
|
|
isPending: false,
|
|
terminalWidth: 80,
|
|
availableTerminalHeight: 40,
|
|
};
|
|
|
|
const mockSettings = new LoadedSettings(
|
|
{ path: '', settings: {} },
|
|
{ path: '', settings: {} },
|
|
{ path: '', settings: {} },
|
|
[],
|
|
true,
|
|
);
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('renders nothing for empty text', () => {
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text="" />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders a simple paragraph', () => {
|
|
const text = 'Hello, world.';
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders headers with correct levels', () => {
|
|
const text = `
|
|
# Header 1
|
|
## Header 2
|
|
### Header 3
|
|
#### Header 4
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders a fenced code block with a language', () => {
|
|
const text = '```javascript\nconst x = 1;\nconsole.log(x);\n```';
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders a fenced code block without a language', () => {
|
|
const text = '```\nplain text\n```';
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('handles unclosed (pending) code blocks', () => {
|
|
const text = '```typescript\nlet y = 2;';
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} isPending={true} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders unordered lists with different markers', () => {
|
|
const text = `
|
|
- item A
|
|
* item B
|
|
+ item C
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders nested unordered lists', () => {
|
|
const text = `
|
|
* Level 1
|
|
* Level 2
|
|
* Level 3
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders ordered lists', () => {
|
|
const text = `
|
|
1. First item
|
|
2. Second item
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders horizontal rules', () => {
|
|
const text = `
|
|
Hello
|
|
---
|
|
World
|
|
***
|
|
Test
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('renders tables correctly', () => {
|
|
const text = `
|
|
| Header 1 | Header 2 |
|
|
|----------|:--------:|
|
|
| Cell 1 | Cell 2 |
|
|
| Cell 3 | Cell 4 |
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('handles a table at the end of the input', () => {
|
|
const text = `
|
|
Some text before.
|
|
| A | B |
|
|
|---|
|
|
| 1 | 2 |`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('inserts a single space between paragraphs', () => {
|
|
const text = `Paragraph 1.
|
|
|
|
Paragraph 2.`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('correctly parses a mix of markdown elements', () => {
|
|
const text = `
|
|
# Main Title
|
|
|
|
Here is a paragraph.
|
|
|
|
- List item 1
|
|
- List item 2
|
|
|
|
\`\`\`
|
|
some code
|
|
\`\`\`
|
|
|
|
Another paragraph.
|
|
`;
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
});
|
|
|
|
it('hides line numbers in code blocks when showLineNumbers is false', () => {
|
|
const text = '```javascript\nconst x = 1;\n```';
|
|
const settings = new LoadedSettings(
|
|
{ path: '', settings: {} },
|
|
{ path: '', settings: { showLineNumbers: false } },
|
|
{ path: '', settings: {} },
|
|
[],
|
|
true,
|
|
);
|
|
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={settings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
expect(lastFrame()).not.toContain(' 1 ');
|
|
});
|
|
|
|
it('shows line numbers in code blocks by default', () => {
|
|
const text = '```javascript\nconst x = 1;\n```';
|
|
const { lastFrame } = render(
|
|
<SettingsContext.Provider value={mockSettings}>
|
|
<MarkdownDisplay {...baseProps} text={text} />
|
|
</SettingsContext.Provider>,
|
|
);
|
|
expect(lastFrame()).toMatchSnapshot();
|
|
expect(lastFrame()).toContain(' 1 ');
|
|
});
|
|
});
|