@@ -274,6 +274,183 @@ describe('processMarkdown', () => {
274274 assert . strictEqual ( result , input ) ;
275275 } ) ;
276276
277+ test ( 'converts img tags to markdown images' , async ( ) => {
278+ const input = dedent `
279+ Some text.
280+
281+ <img src="/assets/blog/devtools.png" style={{ width: '425px' }} />
282+
283+ More text.
284+ ` ;
285+
286+ const { content : result } = await processMarkdown ( input ) ;
287+
288+ assert . ok ( ! result . includes ( '<img' ) ) ;
289+ assert . ok ( result . includes ( '' ) ) ;
290+ assert . ok ( result . includes ( 'Some text.' ) ) ;
291+ assert . ok ( result . includes ( 'More text.' ) ) ;
292+ } ) ;
293+
294+ test ( 'converts img tags with alt text' , async ( ) => {
295+ const input = `<img src="/assets/screenshot.png" alt="App screenshot" />` ;
296+
297+ const { content : result } = await processMarkdown ( input ) ;
298+
299+ assert . strictEqual ( result , '' ) ;
300+ } ) ;
301+
302+ test ( 'converts video tags to source URLs' , async ( ) => {
303+ const input = dedent `
304+ Some text.
305+
306+ <video playsInline autoPlay muted loop style={{ width: '400px', aspectRatio: 4 / 5 }}>
307+ <source src="/assets/icons/sf-symbol.mp4" />
308+ </video>
309+
310+ More text.
311+ ` ;
312+
313+ const { content : result } = await processMarkdown ( input ) ;
314+
315+ assert . ok ( ! result . includes ( '<video' ) ) ;
316+ assert . ok ( ! result . includes ( '<source' ) ) ;
317+ assert . ok ( result . includes ( '/assets/icons/sf-symbol.mp4' ) ) ;
318+ assert . ok ( result . includes ( 'Some text.' ) ) ;
319+ assert . ok ( result . includes ( 'More text.' ) ) ;
320+ } ) ;
321+
322+ test ( 'converts single-line video tags' , async ( ) => {
323+ const input = `<video playsInline autoPlay muted loop><source src="/assets/demo.mp4" /></video>` ;
324+
325+ const { content : result } = await processMarkdown ( input ) ;
326+
327+ assert . strictEqual ( result , '/assets/demo.mp4' ) ;
328+ } ) ;
329+
330+ test ( 'strips device-frame wrapper divs' , async ( ) => {
331+ const input = dedent `
332+ <div className="device-frame">
333+
334+ 
335+
336+ </div>
337+ ` ;
338+
339+ const { content : result } = await processMarkdown ( input ) ;
340+
341+ assert . ok ( ! result . includes ( '<div' ) ) ;
342+ assert . ok ( ! result . includes ( '</div>' ) ) ;
343+ assert . ok ( ! result . includes ( 'device-frame' ) ) ;
344+ assert . ok (
345+ result . includes (
346+ ''
347+ )
348+ ) ;
349+ } ) ;
350+
351+ test ( 'strips image-grid wrapper divs with style' , async ( ) => {
352+ const input = dedent `
353+ <div className="image-grid" style={{ '--img-width': '360px' }}>
354+
355+ 
356+ 
357+
358+ </div>
359+ ` ;
360+
361+ const { content : result } = await processMarkdown ( input ) ;
362+
363+ assert . ok ( ! result . includes ( '<div' ) ) ;
364+ assert . ok ( ! result . includes ( '</div>' ) ) ;
365+ assert . ok ( result . includes ( '' ) ) ;
366+ assert . ok ( result . includes ( '' ) ) ;
367+ } ) ;
368+
369+ test ( 'strips device-frame div wrapping a video' , async ( ) => {
370+ const input = dedent `
371+ <div className="device-frame">
372+ <video playsInline autoPlay muted loop>
373+ <source src="/assets/fundamentals/navigate.mp4" />
374+ </video>
375+ </div>
376+ ` ;
377+
378+ const { content : result } = await processMarkdown ( input ) ;
379+
380+ assert . ok ( ! result . includes ( '<div' ) ) ;
381+ assert . ok ( ! result . includes ( '<video' ) ) ;
382+ assert . ok ( result . includes ( '/assets/fundamentals/navigate.mp4' ) ) ;
383+ } ) ;
384+
385+ test ( 'strips nested decorative divs' , async ( ) => {
386+ const input = dedent `
387+ <div className="outer">
388+ <div className="inner">
389+
390+ Content inside nested divs.
391+
392+ </div>
393+ </div>
394+ ` ;
395+
396+ const { content : result } = await processMarkdown ( input ) ;
397+
398+ assert . ok ( ! result . includes ( '<div' ) ) ;
399+ assert . ok ( ! result . includes ( '</div>' ) ) ;
400+ assert . ok ( result . includes ( 'Content inside nested divs.' ) ) ;
401+ } ) ;
402+
403+ test ( 'strips feature-grid div with video list items' , async ( ) => {
404+ const input = dedent `
405+ <div className="feature-grid">
406+
407+ - <video playsInline autoPlay muted loop><source src="/assets/formsheet.mp4" /></video>
408+
409+ [Form sheet](#form-sheets)
410+
411+ - <video playsInline autoPlay muted loop><source src="/assets/search-bar.mp4" /></video>
412+
413+ [Search bar](#search-bar)
414+
415+ </div>
416+ ` ;
417+
418+ const { content : result } = await processMarkdown ( input ) ;
419+
420+ assert . ok ( ! result . includes ( '<div' ) ) ;
421+ assert . ok ( ! result . includes ( '<video' ) ) ;
422+ assert . ok ( result . includes ( '/assets/formsheet.mp4' ) ) ;
423+ assert . ok ( result . includes ( '[Form sheet](#form-sheets)' ) ) ;
424+ assert . ok ( result . includes ( '/assets/search-bar.mp4' ) ) ;
425+ assert . ok ( result . includes ( '[Search bar](#search-bar)' ) ) ;
426+ } ) ;
427+
428+ test ( 'preserves HTML inside code fences' , async ( ) => {
429+ const input = dedent `
430+ Some text.
431+
432+ \`\`\`jsx
433+ function App() {
434+ return (
435+ <div className="container">
436+ <img src="/logo.png" alt="Logo" />
437+ <video autoPlay>
438+ <source src="/intro.mp4" />
439+ </video>
440+ </div>
441+ );
442+ }
443+ \`\`\`
444+ ` ;
445+
446+ const { content : result } = await processMarkdown ( input ) ;
447+
448+ assert . ok ( result . includes ( '<div className="container">' ) ) ;
449+ assert . ok ( result . includes ( '<img src="/logo.png" alt="Logo" />' ) ) ;
450+ assert . ok ( result . includes ( '<source src="/intro.mp4" />' ) ) ;
451+ assert . ok ( result . includes ( '</div>' ) ) ;
452+ } ) ;
453+
277454 test ( 'strips frontmatter and returns parsed data' , async ( ) => {
278455 const input = dedent `
279456 ---
0 commit comments