mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-06-13 14:23:58 +00:00
fix(webui): handle undefined language in code blocks
When fenced code blocks have no language specifier, react-syntax-highlighter receives undefined for the language prop, causing a white screen crash. - CodeBlock.tsx: fallback to 'text' when language is undefined - MarkdownTextRenderer.tsx: defensive fallback at fence rendering site - Added test cases for both components Fixes #4116
This commit is contained in:
parent
a3241c33ba
commit
bdb3a2ded7
@ -33,7 +33,7 @@ const LazyHighlightedCode = lazy(async () => {
|
|||||||
default({ language, code, isDark }: HighlightedCodeProps) {
|
default({ language, code, isDark }: HighlightedCodeProps) {
|
||||||
return (
|
return (
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
language={language}
|
language={language || "text"}
|
||||||
style={isDark ? oneDark : oneLight}
|
style={isDark ? oneDark : oneLight}
|
||||||
customStyle={{
|
customStyle={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
|
|||||||
@ -264,7 +264,7 @@ export default function MarkdownTextRenderer({
|
|||||||
if (fence) {
|
if (fence) {
|
||||||
return (
|
return (
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
language={fence.language}
|
language={fence.language || "text"}
|
||||||
code={fence.code}
|
code={fence.code}
|
||||||
className="my-3"
|
className="my-3"
|
||||||
highlight={highlightCode}
|
highlight={highlightCode}
|
||||||
|
|||||||
@ -48,6 +48,22 @@ describe("CodeBlock", () => {
|
|||||||
expect(screen.getByTestId("plain-code-fallback")).toHaveClass("text-foreground/90");
|
expect(screen.getByTestId("plain-code-fallback")).toHaveClass("text-foreground/90");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("falls back to 'text' language when language is undefined", async () => {
|
||||||
|
render(
|
||||||
|
<ThemeProvider theme="dark">
|
||||||
|
<CodeBlock language={undefined} code="const value = 1;" />
|
||||||
|
</ThemeProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId("highlighted-code")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("const value = 1;")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it("reads theme from context without creating per-block observers", async () => {
|
it("reads theme from context without creating per-block observers", async () => {
|
||||||
const originalMutationObserver = globalThis.MutationObserver;
|
const originalMutationObserver = globalThis.MutationObserver;
|
||||||
const observer = vi.fn();
|
const observer = vi.fn();
|
||||||
|
|||||||
@ -16,6 +16,17 @@ describe("MarkdownTextRenderer", () => {
|
|||||||
expect(container.querySelector("pre div")).toBeNull();
|
expect(container.querySelector("pre div")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("renders bare fenced code blocks without crashing", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<MarkdownTextRenderer highlightCode={false}>
|
||||||
|
{"Some text\n\n```\ncode without language\n```"}
|
||||||
|
</MarkdownTextRenderer>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("code without language")).toBeInTheDocument();
|
||||||
|
expect(container.querySelectorAll("pre")).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps streaming unfinished fenced code blocks to a single shell", () => {
|
it("keeps streaming unfinished fenced code blocks to a single shell", () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<MarkdownTextRenderer highlightCode={false}>
|
<MarkdownTextRenderer highlightCode={false}>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user