Skip to content

Commit 97d0998

Browse files
authored
Markdown: fix img alt containing markup (#261)
1 parent 897e880 commit 97d0998

2 files changed

Lines changed: 48 additions & 37 deletions

File tree

src/components/Markdown/Markdown.test.tsx

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,22 @@ describe('Markdown code blocks', () => {
127127
expect(code?.textContent).toBe('console.log(\'Hello, world!\')')
128128
})
129129

130-
it('renders an unterminated code block', () => {
130+
it('unterminated code block', () => {
131131
const text = '```js\nconsole.log(\'Hello, world!\')'
132132
const { container } = render(<Markdown text={text} />)
133133
const code = container.querySelector('pre')
134134
expect(code).toBeDefined()
135135
expect(code?.textContent).toBe('console.log(\'Hello, world!\')')
136136
})
137137

138-
it('renders a bold code block', () => {
138+
it('bold code block', () => {
139139
const text = '**`Math.pow(base, exponent)`**'
140140
const { container, getByText } = render(<Markdown text={text} />)
141141
expect(getByText('Math.pow(base, exponent)')).toBeDefined()
142142
expect(container.innerHTML).not.toContain('**')
143143
})
144144

145-
it('renders markdown inside a code block as literal text', () => {
145+
it('markdown inside a code block as literal text', () => {
146146
const text = `\`\`\`
147147
**This should not be bold**
148148
*nor italic*
@@ -169,15 +169,15 @@ describe('Markdown lists', () => {
169169
expect(container.querySelectorAll('p').length).toBe(0)
170170
})
171171

172-
it('renders a list with bold', () => {
172+
it('list with bold', () => {
173173
const text = '- **Item 1**\n- Item 2\n- Item 3\n\n'
174174
const { getByText } = render(<Markdown text={text} />)
175175
expect(getByText('Item 1')).toBeDefined()
176176
expect(getByText('Item 2')).toBeDefined()
177177
expect(getByText('Item 3')).toBeDefined()
178178
})
179179

180-
it('renders a list with indented sub-paragraphs', () => {
180+
it('list with indented sub-paragraphs', () => {
181181
const text = '- Item 1\n Paragraph 1\n Paragraph 2\n- Item 2\n\n'
182182
const { container, getByText } = render(<Markdown text={text} />)
183183
expect(getByText('Item 1')).toBeDefined()
@@ -188,13 +188,13 @@ describe('Markdown lists', () => {
188188
expect(container.querySelectorAll('p').length).toBe(2)
189189
})
190190

191-
it('renders an unterminated list', () => {
191+
it('unterminated list', () => {
192192
const text = '- Item 1'
193193
const { getByText } = render(<Markdown text={text} />)
194194
expect(getByText('Item 1')).toBeDefined()
195195
})
196196

197-
it('renders nested unordered list with sub-items', () => {
197+
it('nested unordered list with sub-items', () => {
198198
const text = `- Parent item
199199
- Child item
200200
- Grandchild item`
@@ -204,7 +204,7 @@ describe('Markdown lists', () => {
204204
expect(getByText('Grandchild item')).toBeDefined()
205205
})
206206

207-
it('renders nested ordered list', () => {
207+
it('nested ordered list', () => {
208208
const text = `1. First item
209209
1. Nested item
210210
2. Another nested item
@@ -216,7 +216,7 @@ describe('Markdown lists', () => {
216216
expect(getByText('Second item')).toBeDefined()
217217
})
218218

219-
it('handles blank lines in lists', () => {
219+
it('blank lines in lists', () => {
220220
const text = '- Item 1\n\n- Item 2\n\n- Item 3'
221221
const { container, getByText } = render(<Markdown text={text} />)
222222
expect(getByText('Item 1')).toBeDefined()
@@ -226,7 +226,7 @@ describe('Markdown lists', () => {
226226
expect(container.querySelectorAll('li').length).toBe(3)
227227
})
228228

229-
it('renders inline code inside a nested list with mixed formatting', () => {
229+
it('inline code inside a nested list with mixed formatting', () => {
230230
const text = `- Item with inline code: \`const x = 10;\`
231231
- Child item with **bold** text and \`inline code\``
232232
const { getByText, container } = render(<Markdown text={text} />)
@@ -240,7 +240,7 @@ describe('Markdown lists', () => {
240240
expect(inlineCodes.length).toBe(2)
241241
})
242242

243-
it('renders a nested code block within a list item', () => {
243+
it('nested code block within a list item', () => {
244244
const text = `- List item with code:
245245
\`\`\`js
246246
console.log("Nested code")
@@ -253,15 +253,15 @@ describe('Markdown lists', () => {
253253
expect(codeBlock?.textContent).toContain('console.log("Nested code")')
254254
})
255255

256-
it('renders a list with unicode dash –', () => {
256+
it('list with unicode dash –', () => {
257257
const text = '– Item 1\n– Item 2\n– Item 3\n\n'
258258
const { getByText } = render(<Markdown text={text} />)
259259
expect(getByText('Item 1')).toBeDefined()
260260
expect(getByText('Item 2')).toBeDefined()
261261
expect(getByText('Item 3')).toBeDefined()
262262
})
263263

264-
it('renders a list with unicode dot •', () => {
264+
it('list with unicode dot •', () => {
265265
const text = '• Item 1\n• Item 2\n• Item 3\n\n'
266266
const { getByText } = render(<Markdown text={text} />)
267267
expect(getByText('Item 1')).toBeDefined()
@@ -270,24 +270,8 @@ describe('Markdown lists', () => {
270270
})
271271
})
272272

273-
describe('Markdown with nested elements', () => {
274-
it('renders nested formatting with bold, italic, and inline code', () => {
275-
const text = 'This is **bold text with *italic and `code` inside* text**.'
276-
const { container } = render(<Markdown text={text} />)
277-
// Check for inline code element
278-
const codeElem = container.querySelector('code')
279-
expect(codeElem).toBeDefined()
280-
// Check for italic element that should contain the inline code
281-
const italicElem = container.querySelector('em')
282-
expect(italicElem).toBeDefined()
283-
expect(italicElem?.textContent).toContain('code')
284-
// The bold text should wrap the entire content
285-
const boldElem = container.querySelector('strong')
286-
expect(boldElem).toBeDefined()
287-
expect(boldElem?.textContent).toContain('bold text with')
288-
})
289-
290-
it('renders an image inside a link', () => {
273+
describe('Markdown images', () => {
274+
it('image inside a link', () => {
291275
const text = '[![mit license](https://img.shields.io/badge/License-MIT-orange.svg)](https://opensource.org/licenses/MIT)'
292276
const { container } = render(<Markdown text={text} />)
293277

@@ -304,7 +288,7 @@ describe('Markdown with nested elements', () => {
304288
expect(link?.contains(img)).toBe(true)
305289
})
306290

307-
it('handles multiple images inside links in one paragraph', () => {
291+
it('multiple images inside links in one paragraph', () => {
308292
const text = 'Check [![license](https://img.shields.io/badge/License-MIT-orange.svg)](https://opensource.org/licenses/MIT) and [![npm](https://img.shields.io/npm/v/package.svg)](https://www.npmjs.com/package)'
309293
const { container } = render(<Markdown text={text} />)
310294

@@ -328,7 +312,7 @@ describe('Markdown with nested elements', () => {
328312
expect(images[1].getAttribute('alt')).toBe('npm')
329313
})
330314

331-
it('handles images and text inside links', () => {
315+
it('images and text inside links', () => {
332316
const text = '[Click here ![icon](https://example.com/icon.png) for more info](https://example.com)'
333317
const { container } = render(<Markdown text={text} />)
334318

@@ -348,22 +332,48 @@ describe('Markdown with nested elements', () => {
348332
expect(link?.contains(img)).toBe(true)
349333
})
350334

351-
it('handles incomplete image syntax without closing bracket', () => {
335+
it('incomplete image syntax without closing bracket', () => {
352336
const text = '![alt'
353337
const { container } = render(<Markdown text={text} />)
354338

355339
expect(container.textContent).toBe('![alt')
356340
expect(container.querySelector('img')).toBeNull()
357341
})
358342

359-
it('handles incomplete image syntax without closing parenthesis', () => {
343+
it('incomplete image syntax without closing parenthesis', () => {
360344
const text = '![alt](https://example.com/image.png'
361345
const { container } = render(<Markdown text={text} />)
362346

363347
expect(container.textContent).toBe('![alt](https://example.com/image.png')
364348
expect(container.querySelector('img')).toBeNull()
365349
})
366350

351+
describe('image alt text', () => {
352+
it('keeps inline code', () => {
353+
const md = '![Press `Ctrl+C`](keys.png)'
354+
const { container } = render(<Markdown text={md} />)
355+
expect(container.querySelector('img')?.alt).toBe('Press Ctrl+C')
356+
})
357+
})
358+
})
359+
360+
describe('Markdown with nested elements', () => {
361+
it('renders nested formatting with bold, italic, and inline code', () => {
362+
const text = 'This is **bold text with *italic and `code` inside* text**.'
363+
const { container } = render(<Markdown text={text} />)
364+
// Check for inline code element
365+
const codeElem = container.querySelector('code')
366+
expect(codeElem).toBeDefined()
367+
// Check for italic element that should contain the inline code
368+
const italicElem = container.querySelector('em')
369+
expect(italicElem).toBeDefined()
370+
expect(italicElem?.textContent).toContain('code')
371+
// The bold text should wrap the entire content
372+
const boldElem = container.querySelector('strong')
373+
expect(boldElem).toBeDefined()
374+
expect(boldElem?.textContent).toContain('bold text with')
375+
})
376+
367377
it('handles incomplete link syntax without closing bracket', () => {
368378
const text = '[link'
369379
const { container } = render(<Markdown text={text} />)
@@ -413,15 +423,15 @@ describe('Markdown with tables', () => {
413423
expect(getByText('Data 2')).toBeDefined()
414424
})
415425

416-
it('renders a table that omits the outer pipes', () => {
426+
it('table that omits the outer pipes', () => {
417427
const text = 'Header A | Header B\n---|---\nCell 1 | Cell 2'
418428
const { getByText, getByRole } = render(<Markdown text={text} />)
419429
expect(getByRole('table')).toBeDefined()
420430
expect(getByText('Header A')).toBeDefined()
421431
expect(getByText('Cell 2')).toBeDefined()
422432
})
423433

424-
it('renders inline formatting inside cells', () => {
434+
it('inline formatting inside cells', () => {
425435
const text = '| **Bold** | Link |\n|-----------|------|\n| `code` | [x](#) |'
426436
const { getByText, getByRole } = render(<Markdown text={text} />)
427437
expect(getByRole('table')).toBeDefined()

src/components/Markdown/Markdown.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ function tokensToString(tokens: Token[]): string {
253253
.map(token => {
254254
switch (token.type) {
255255
case 'text':
256+
case 'code':
256257
return token.content
257258
case 'bold':
258259
case 'italic':

0 commit comments

Comments
 (0)