From 28b617dd738b0c3c5ec56359a2a8546285253212 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sun, 26 Jul 2026 14:41:23 +0800 Subject: [PATCH] test(ui-primitives): cover the fence pre-routing arms; drop the unreachable array probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI coverage flagged MarkdownText's pre route: the array-element probe (raw[0]) and the mixed-content fallbacks were unreachable — the markdown pipeline hands pre one code element whose children are one string (or none, for an empty fence). Simplify to the string check, annotate the isValidElement guard as representation-change armor, and pin both live arms: the empty fence keeps the stock
, a language-less fence renders
the plain CodeBlock arm.
---
.../client/ui-primitives/src/markdown/MarkdownText.tsx | 10 +++++-----
packages/client/ui-primitives/tests/markdown.spec.tsx | 9 +++++++++
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/packages/client/ui-primitives/src/markdown/MarkdownText.tsx b/packages/client/ui-primitives/src/markdown/MarkdownText.tsx
index 79ebc5f1b2..775978a275 100644
--- a/packages/client/ui-primitives/src/markdown/MarkdownText.tsx
+++ b/packages/client/ui-primitives/src/markdown/MarkdownText.tsx
@@ -53,14 +53,14 @@ function buildComponents(streaming: boolean): Components {
// plain arm — retokenizing a growing fence on every chunk is quadratic
// main-thread work; the finalize swap highlights it once.
pre: ({ children }) => {
+ /* v8 ignore next 2 -- the markdown pipeline always hands `pre` its single `code` element; the undefined arm guards a react-markdown representation change. */
const child = isValidElement<{ className?: string; children?: unknown }>(children) ? children : undefined
const raw = child?.props.children
- const text = typeof raw === 'string' ? raw : Array.isArray(raw) && typeof raw[0] === 'string' ? raw[0] : undefined
- // A fence whose content isn't one plain string (never produced by the
- // markdown pipeline) keeps the stock rather than guessing.
- if (text === undefined) return {children}
+ // A fence whose content isn't one plain string (e.g. an empty fence)
+ // keeps the stock rather than guessing.
+ if (typeof raw !== 'string') return {children}
const lang = /language-([\w-]+)/.exec(child?.props.className ?? '')?.[1]
- return
+ return
},
}
}
diff --git a/packages/client/ui-primitives/tests/markdown.spec.tsx b/packages/client/ui-primitives/tests/markdown.spec.tsx
index 1bd629a7d0..00de9683ff 100644
--- a/packages/client/ui-primitives/tests/markdown.spec.tsx
+++ b/packages/client/ui-primitives/tests/markdown.spec.tsx
@@ -64,6 +64,15 @@ describe('MarkdownText', () => {
expect(screen.getByRole('link', { name: 'https://deepseek.com' })).toBeTruthy()
})
+ it('an empty fence keeps the stock pre; a language-less fence renders the plain CodeBlock arm', () => {
+ const empty = render( )
+ expect(empty.container.querySelector('pre')?.outerHTML).toBe('
')
+
+ const plain = render( )
+ expect(plain.container.querySelector('pre.shiki')).toBeNull()
+ expect(plain.container.querySelector('pre code')?.textContent).toContain('no language here')
+ })
+
it('streaming renders fences plain; the finalize swap highlights them', () => {
const fence = '```ts\nconst answer = 42\n```'
const live = render( )