From eacb3e053daeac2f9de94fcd43694669542d25fe Mon Sep 17 00:00:00 2001 From: "(CJ) Chukwudi Nwobodo" <142016413+chuks-qua@users.noreply.github.com> Date: Thu, 24 Sep 2026 11:21:54 +0100 Subject: [PATCH] fix(web): keep message text visible while markdown content suspends --- .../conversation/messages/MessageBubble.tsx | 4 +- .../__tests__/MessageBubble.suspense.test.tsx | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/features/conversation/messages/__tests__/MessageBubble.suspense.test.tsx diff --git a/apps/web/src/features/conversation/messages/MessageBubble.tsx b/apps/web/src/features/conversation/messages/MessageBubble.tsx index 41c946f5e..a350c1d2a 100644 --- a/apps/web/src/features/conversation/messages/MessageBubble.tsx +++ b/apps/web/src/features/conversation/messages/MessageBubble.tsx @@ -631,7 +631,7 @@ function UserMessageText({ message, displayText, userGoal }: { message: Message; {hasMentions ? ( ) : ( - + {displayText}

}>
)} @@ -854,7 +854,7 @@ function AssistantResponseText({ {renderDelta ? ( ) : ( - + {message.content}

}>
)} diff --git a/apps/web/src/features/conversation/messages/__tests__/MessageBubble.suspense.test.tsx b/apps/web/src/features/conversation/messages/__tests__/MessageBubble.suspense.test.tsx new file mode 100644 index 000000000..6e9c78905 --- /dev/null +++ b/apps/web/src/features/conversation/messages/__tests__/MessageBubble.suspense.test.tsx @@ -0,0 +1,57 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { cleanup, render } from "@testing-library/react"; +import type { Message, StoredAttachment } from "@/transport"; +import { MessageBubble } from "../MessageBubble"; +import { createEmptyThreadRecord } from "@/stores/thread-record"; +import { resetThreadStoreForTests } from "@/stores/thread-store-test-utils"; + +vi.mock("@/components/chat/MarkdownContent", () => { + const SuspendedMarkdownContent = () => { + throw new Promise(() => {}); + }; + return { + __esModule: true, + default: SuspendedMarkdownContent, + MarkdownContent: SuspendedMarkdownContent, + }; +}); + +beforeEach(() => { + resetThreadStoreForTests({ records: new Map([["thread-1", createEmptyThreadRecord()]]) }); +}); + +afterEach(() => { + cleanup(); +}); + +function makeMessage(content: string, role: "user" | "assistant" = "user"): Message { + return { + id: "msg-1", + thread_id: "thread-1", + role, + content, + timestamp: new Date().toISOString(), + attachments: [] as StoredAttachment[], + cost_usd: null, + tokens_used: null, + sequence: 1, + tool_calls: null, + files_changed: null, + }; +} + +describe("MessageBubble while MarkdownContent is suspended", () => { + it("keeps the user text visible in the bubble instead of rendering it empty", () => { + const { container } = render(); + const bubble = container.querySelector(".bg-accent"); + expect(bubble).not.toBeNull(); + expect(bubble?.textContent).toContain("hello there"); + }); + + it("keeps the assistant text visible instead of rendering it empty", () => { + const { container } = render(); + const body = container.querySelector("[data-testid='assistant-response-text']"); + expect(body).not.toBeNull(); + expect(body?.textContent).toContain("done."); + }); +});