Skip to content

Commit 3c5fbb4

Browse files
bytranglelouis-janCopilot
authored
fix: Support Remark Line Breaks in Agent Response (#6818)
* support remark line breaks consistently * remove console.log * test line break preservation for RenderMarkdown * Update web-app/src/containers/__tests__/RenderMarkdown.test.tsx Co-authored-by: Copilot <[email protected]> * Update web-app/src/containers/__tests__/RenderMarkdown.test.tsx Co-authored-by: Copilot <[email protected]> * Update web-app/src/containers/__tests__/RenderMarkdown.test.tsx Co-authored-by: Copilot <[email protected]> * Update web-app/src/containers/__tests__/RenderMarkdown.test.tsx Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Louis <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent b2a8efd commit 3c5fbb4

File tree

2 files changed

+81
-6
lines changed

2 files changed

+81
-6
lines changed

web-app/src/containers/RenderMarkdown.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,8 @@ function RenderMarkdownComponent({
229229

230230
// Stable remarkPlugins reference
231231
const remarkPlugins = useMemo(() => {
232-
const basePlugins = [remarkGfm, remarkMath, remarkEmoji]
233-
if (isUser) {
234-
basePlugins.push(remarkBreaks)
235-
}
236-
return basePlugins
237-
}, [isUser])
232+
return [remarkGfm, remarkMath, remarkEmoji, remarkBreaks]
233+
}, [])
238234

239235
// Stable rehypePlugins reference
240236
const rehypePlugins = useMemo(() => {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { describe, it, expect, vi } from 'vitest';
3+
import { RenderMarkdown } from '../RenderMarkdown';
4+
5+
vi.mock('@i18n/react-i18next-compat', () => ({
6+
useTranslation: () => ({
7+
t: (key: string) => key
8+
})
9+
}))
10+
11+
// Mock clipboard API
12+
Object.assign(navigator, {
13+
clipboard: {
14+
writeText: vi.fn()
15+
}
16+
})
17+
18+
describe('RenderMarkdown', () => {
19+
it('preserves line breaks in model responses (when isUser == undefined)', () => {
20+
const modelResponseWithNewLines = `This is line 1
21+
This is line 2
22+
This is line 3`
23+
render (
24+
<RenderMarkdown
25+
content={modelResponseWithNewLines}
26+
/>
27+
)
28+
const markdownContainer = document.querySelector('.markdown')
29+
expect(markdownContainer?.innerHTML).toContain('<br>')
30+
// Match either <br> or <br/>
31+
const brCount = (markdownContainer?.innerHTML.match(/<br\s*\/?>/g) || []).length
32+
expect(brCount).toBe(2)
33+
})
34+
35+
it('preserves line breaks in user message (when isUser == true)', () => {
36+
const userMessageWithNewlines = `User question line 1
37+
User question line 2
38+
User question line 3`
39+
render(
40+
<RenderMarkdown
41+
content={userMessageWithNewlines}
42+
isUser={true}
43+
/>
44+
)
45+
const markdownContainer = document.querySelector('.markdown')
46+
expect(markdownContainer).toBeTruthy()
47+
expect(markdownContainer?.innerHTML).toContain('<br>')
48+
const brCount = (markdownContainer?.innerHTML.match(/<br\s*\/?>/g) || []).length
49+
expect(brCount).toBe(2)
50+
})
51+
52+
it('preserves line breaks with different line ending types', () => {
53+
const contentWithDifferentLineEndings = "Line1\nLine2\r\nLine3\rLine4"
54+
render(
55+
<RenderMarkdown
56+
content={contentWithDifferentLineEndings}
57+
/>
58+
)
59+
const markdownContainer = document.querySelector('.markdown')
60+
expect(markdownContainer?.innerHTML).toContain('<br>')
61+
const brCount = (markdownContainer?.innerHTML.match(/<br\s*\/?>/g) || []).length
62+
expect(brCount).toBe(3)
63+
})
64+
65+
it('handles empty lines correctly', () => {
66+
const contentWithEmptyLines = 'Line 1\n\nLine 3 (after empty line)\n\nLine 5 (after two empty lines)'
67+
render(
68+
<RenderMarkdown
69+
content={contentWithEmptyLines}
70+
/>
71+
)
72+
const markdownContainer = document.querySelector('.markdown')
73+
const html = markdownContainer?.innerHTML || ''
74+
// Double new lines (`\n\n`) creates paragraph breaks, not line breaks
75+
expect(html).not.toContain('<br>')
76+
const paragraphCount = (html.match(/<p>/g) || []).length
77+
expect(paragraphCount).toBe(3) // Expect 3 paragraphs for 2 empty lines
78+
})
79+
})

0 commit comments

Comments
 (0)