import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { MessageItem } from "./MessageItem";
vi.mock("../api/settings", () => ({
settingsApi: {
openFile: vi.fn(() => Promise.resolve({ success: true })),
},
}));
describe("MessageItem component (Story 178 AC3)", () => {
it("renders user message as a bubble", () => {
render();
expect(screen.getByText("Hello there!")).toBeInTheDocument();
});
it("renders assistant message with markdown-body class", () => {
render(
,
);
expect(screen.getByText("Here is my response.")).toBeInTheDocument();
const text = screen.getByText("Here is my response.");
expect(text.closest(".markdown-body")).toBeTruthy();
});
it("renders tool message as collapsible details", () => {
render(
,
);
expect(screen.getByText(/Tool Output/)).toBeInTheDocument();
});
it("renders tool call badges for assistant messages with tool_calls", () => {
render(
,
);
expect(screen.getByText("I will read the file.")).toBeInTheDocument();
expect(screen.getByText("Read(src/main.rs)")).toBeInTheDocument();
});
it("is wrapped in React.memo (has displayName or $$typeof memo)", () => {
// React.memo wraps the component — verify the export is memoized
// by checking that the component has a memo wrapper
const { type } = { type: MessageItem };
// React.memo returns an object with $$typeof === Symbol(react.memo)
// biome-ignore lint/suspicious/noExplicitAny: checking React internals for test
expect((type as any).$$typeof).toBeDefined();
// biome-ignore lint/suspicious/noExplicitAny: checking React internals for test
const typeofStr = String((type as any).$$typeof);
expect(typeofStr).toContain("memo");
});
});
describe("MessageItem code reference rendering (Story 193)", () => {
it("renders inline code with a code reference as a clickable button in assistant messages", () => {
render(
,
);
const button = screen.getByRole("button", { name: /src\/main\.rs:42/ });
expect(button).toBeInTheDocument();
});
});
describe("MessageItem user message code fence rendering (Story 196)", () => {
it("renders code fences in user messages as code blocks", () => {
const { container } = render(
,
);
// Syntax highlighter renders a pre > div > code structure
const codeEl = container.querySelector("pre code");
expect(codeEl).toBeInTheDocument();
expect(codeEl?.textContent).toContain("console.log");
});
it("renders inline code with single backticks in user messages", () => {
render(
,
);
const codeEl = screen.getByText("npm install");
expect(codeEl.tagName.toLowerCase()).toBe("code");
});
it("renders user messages with code blocks inside user-markdown-body class", () => {
const { container } = render(
,
);
expect(container.querySelector(".user-markdown-body")).toBeTruthy();
});
});