import { EnvironmentId, MessageId } from "@t3tools/contracts";
import { createRef, type ReactNode, type Ref } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { beforeAll, describe, expect, it, vi } from "vite-plus/test";
import type { LegendListRef } from "@legendapp/list/react";
vi.mock("@legendapp/list/react", async () => {
const legendListTestId = "legend-list";
const LegendList = (props: {
data: Array<{ id: string }>;
keyExtractor: (item: { id: string }) => string;
renderItem: (args: { item: { id: string } }) => ReactNode;
ListHeaderComponent?: ReactNode;
ListFooterComponent?: ReactNode;
ref?: Ref;
}) => (
{props.ListHeaderComponent}
{props.data.map((item) => (
{props.renderItem({ item })}
))}
{props.ListFooterComponent}
);
return { LegendList };
});
function MockFileDiff(props: {
fileDiff: { name?: string | null; prevName?: string | null };
renderCustomHeader?: (fileDiff: {
name?: string | null;
prevName?: string | null;
}) => React.ReactNode;
}) {
return (
{props.renderCustomHeader?.(props.fileDiff)}
{props.fileDiff.name ?? props.fileDiff.prevName ?? "diff"}
);
}
vi.mock("@pierre/diffs/react", () => {
return { FileDiff: MockFileDiff };
});
function matchMedia() {
return {
matches: false,
addEventListener: () => {},
removeEventListener: () => {},
};
}
beforeAll(() => {
const classList = {
add: () => {},
remove: () => {},
toggle: () => {},
contains: () => false,
};
vi.stubGlobal("localStorage", {
getItem: () => null,
setItem: () => {},
removeItem: () => {},
clear: () => {},
});
vi.stubGlobal("window", {
matchMedia,
addEventListener: () => {},
removeEventListener: () => {},
requestAnimationFrame: (callback: FrameRequestCallback) => {
callback(0);
return 0;
},
cancelAnimationFrame: () => {},
desktopBridge: undefined,
});
vi.stubGlobal("document", {
documentElement: {
classList,
offsetHeight: 0,
},
});
});
const ACTIVE_THREAD_ENVIRONMENT_ID = EnvironmentId.make("environment-local");
const MESSAGE_CREATED_AT = "2026-03-17T19:12:28.000Z";
function buildProps() {
return {
isWorking: false,
activeTurnInProgress: false,
activeTurnStartedAt: null,
listRef: createRef(),
latestTurn: null,
turnDiffSummaryByAssistantMessageId: new Map(),
routeThreadKey: "environment-local:thread-1",
onOpenTurnDiff: () => {},
revertTurnCountByUserMessageId: new Map(),
onRevertUserMessage: () => {},
isRevertingCheckpoint: false,
onImageExpand: () => {},
activeThreadEnvironmentId: ACTIVE_THREAD_ENVIRONMENT_ID,
markdownCwd: undefined,
resolvedTheme: "light" as const,
timestampFormat: "locale" as const,
workspaceRoot: undefined,
onIsAtEndChange: () => {},
};
}
function buildLongUserMessageText(tail = "deep hidden detail only after expand") {
return Array.from({ length: 9 }, (_, index) =>
index === 8 ? tail : `Line ${index + 1}: ${"verbose prompt content ".repeat(8).trim()}`,
).join("\n");
}
function buildUserTimelineEntry(text: string) {
return {
id: "entry-1",
kind: "message" as const,
createdAt: MESSAGE_CREATED_AT,
message: {
id: MessageId.make("message-1"),
role: "user" as const,
text,
turnId: null,
createdAt: MESSAGE_CREATED_AT,
updatedAt: MESSAGE_CREATED_AT,
streaming: false,
},
};
}
describe("MessagesTimeline", () => {
it("renders collapse controls for long user messages", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).toContain("Show full message");
expect(markup).toContain('data-user-message-collapsed="true"');
expect(markup).toContain('data-user-message-fade="true"');
expect(markup).toContain('data-user-message-footer="true"');
});
it("does not render collapse controls for short user messages", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).not.toContain("Show full message");
expect(markup).toContain('data-user-message-collapsible="false"');
});
it("renders inline terminal labels with the composer chip UI", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
",
"- Terminal 1 lines 1-5:",
" 1 | julius@mac effect-http-ws-cli % bun i",
" 2 | bun install v1.3.9 (cf6cdbbb)",
"",
].join("\n"),
),
]}
/>,
);
expect(markup).toContain("Terminal 1 lines 1-5");
expect(markup).toContain("lucide-terminal");
expect(markup).toContain("yoo what's
");
expect(markup).toContain(' ');
expect(markup).toContain("Show full message");
}, 20_000);
it("keeps the copy button for collapsed long user messages", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).toContain('aria-label="Copy link"');
expect(markup).toContain('data-user-message-collapsed="true"');
expect(markup).toContain('data-user-message-footer="true"');
});
it("renders context compaction entries in the normal work log", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).toContain("Context compacted");
expect(markup).toContain("Work Log");
});
it("formats changed file paths from the workspace root", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).toContain("t3code/apps/web/src/session-logic.ts");
expect(markup).not.toContain("C:/Users/mike/dev-stuff/t3code/apps/web/src/session-logic.ts");
});
it("renders review comment contexts as structured cards instead of raw tags", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
',
"Wadduo",
"```diff",
"@@ -0,0 +47,2 @@",
'+ it("keeps valid zero-usage snapshots", () => {',
"+ expect(snapshot).not.toBeNull();",
"```",
"",
].join("\n"),
turnId: null,
createdAt: "2026-03-17T19:12:28.000Z",
updatedAt: "2026-03-17T19:12:28.000Z",
streaming: false,
},
},
]}
/>,
);
expect(markup).toContain("contextWindow.test.ts");
expect(markup).toContain("Wadduo");
expect(markup).toContain('data-testid="file-diff"');
expect(markup).not.toContain(">Review comment<");
expect(markup).not.toContain("<review_comment");
expect(markup).not.toContain("</review_comment>");
});
it("renders file review comments as source code instead of diffs", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
',
"Clarify this.",
"```md",
"# Plan",
"- Step one",
"```",
"",
].join("\n"),
turnId: null,
createdAt: "2026-03-17T19:12:28.000Z",
updatedAt: "2026-03-17T19:12:28.000Z",
streaming: false,
},
},
]}
/>,
);
expect(markup).toContain("plan.md");
expect(markup).toContain("Clarify this.");
expect(markup).toContain("# Plan");
expect(markup).not.toContain('data-testid="file-diff"');
});
it("renders a failure marker for failed tool lifecycle entries", async () => {
const { MessagesTimeline } = await import("./MessagesTimeline");
const markup = renderToStaticMarkup(
,
);
expect(markup).toContain("lucide-x");
expect(markup).toContain('aria-label="Tool call failed"');
});
});