





















@@ -27,6 +27,23 @@ function firstMessageContent(group: MessageGroup): unknown[] {
2727return Array.isArray(message.content) ? message.content : [];
2828}
292930+function requireRecord(value: unknown): Record<string, unknown> {
31+expect(value).toBeTruthy();
32+expect(typeof value).toBe("object");
33+expect(Array.isArray(value)).toBe(false);
34+return value as Record<string, unknown>;
35+}
36+37+function requireGroup(value: unknown): MessageGroup {
38+const record = requireRecord(value);
39+expect(record.kind).toBe("group");
40+return value as MessageGroup;
41+}
42+43+function messageRecord(group: MessageGroup, index = 0): Record<string, unknown> {
44+return requireRecord(group.messages[index]?.message);
45+}
46+3047describe("buildChatItems", () => {
3148it("keeps consecutive user messages from different senders in separate groups", () => {
3249const groups = messageGroups({
@@ -61,7 +78,7 @@ describe("buildChatItems", () => {
61786279expect(groups).toHaveLength(1);
6380expect(groups[0].messages).toHaveLength(1);
64-expect(groups[0].messages[0]).toMatchObject({ duplicateCount: 3 });
81+expect(groups[0].messages[0].duplicateCount).toBe(3);
6582});
66836784it("suppresses assistant HEARTBEAT_OK acknowledgements before rendering history", () => {
@@ -77,9 +94,9 @@ describe("buildChatItems", () => {
7794expect(groups).toHaveLength(2);
7895expect(groups[0].role).toBe("user");
7996expect(groups[1].role).toBe("assistant");
80-expect(groups[1].messages[0].message).toMatchObject({
81-content: [{ type: "text", text: "Visible reply" }],
82-});
97+expect(messageRecord(groups[1]).content).toStrictEqual([
98+{ type: "text", text: "Visible reply" },
99+]);
83100});
8410185102it("suppresses assistant HEARTBEAT_OK acknowledgements that carry hidden thinking blocks", () => {
@@ -118,12 +135,10 @@ describe("buildChatItems", () => {
118135119136expect(groups).toHaveLength(1);
120137expect(groups[0].messages).toHaveLength(1);
121-expect(groups[0].messages[0].message).toMatchObject({
122-content: [
123-{ type: "thinking", thinking: "Useful hidden reasoning." },
124-{ type: "text", text: "Visible reply" },
125-],
126-});
138+expect(messageRecord(groups[0]).content).toStrictEqual([
139+{ type: "thinking", thinking: "Useful hidden reasoning." },
140+{ type: "text", text: "Visible reply" },
141+]);
127142});
128143129144it("keeps HEARTBEAT_OK turns that carry visible non-text content", () => {
@@ -211,24 +226,14 @@ describe("buildChatItems", () => {
211226212227const groups = items.filter((item) => item.kind === "group");
213228214-expect(items[0]).toMatchObject({
215-kind: "group",
216-messages: [
217-expect.objectContaining({
218-message: expect.objectContaining({
219-role: "system",
220-content: "Showing last 100 messages (5 hidden).",
221-}),
222-}),
223-],
224-});
229+const noticeGroup = requireGroup(items[0]);
230+expect(noticeGroup.messages).toHaveLength(1);
231+const noticeMessage = messageRecord(noticeGroup);
232+expect(noticeMessage.role).toBe("system");
233+expect(noticeMessage.content).toBe("Showing last 100 messages (5 hidden).");
225234expect(groups).toHaveLength(101);
226-expect(groups[1].messages[0].message).toMatchObject({
227-content: "message 5",
228-});
229-expect(groups.at(-1)?.messages[0].message).toMatchObject({
230-content: "message 104",
231-});
235+expect(messageRecord(groups[1]).content).toBe("message 5");
236+expect(messageRecord(groups[groups.length - 1]).content).toBe("message 104");
232237});
233238234239it("does not collapse duplicate text messages separated by another message", () => {
@@ -435,12 +440,10 @@ describe("buildChatItems", () => {
435440436441const canvasBlocks = canvasBlocksIn(groups[0]);
437442expect(canvasBlocks).toHaveLength(1);
438-expect(canvasBlocks[0]).toMatchObject({
439-preview: {
440-viewId: "cv_streamed_artifact",
441-title: "Streamed demo",
442-},
443-});
443+const canvasBlock = requireRecord(canvasBlocks[0]);
444+const preview = requireRecord(canvasBlock.preview);
445+expect(preview.viewId).toBe("cv_streamed_artifact");
446+expect(preview.title).toBe("Streamed demo");
444447});
445448446449it("explains compaction boundaries and exposes the checkpoint action", () => {
@@ -460,16 +463,15 @@ describe("buildChatItems", () => {
460463);
461464462465expect(items).toHaveLength(1);
463-expect(items[0]).toMatchObject({
464-kind: "divider",
465-label: "Compacted history",
466-description:
467-"Earlier turns are preserved in a compaction checkpoint. Open session checkpoints to branch or restore that pre-compaction view.",
468-action: {
469-kind: "session-checkpoints",
470-label: "Open checkpoints",
471-},
472-});
466+const divider = requireRecord(items[0]);
467+expect(divider.kind).toBe("divider");
468+expect(divider.label).toBe("Compacted history");
469+expect(divider.description).toBe(
470+"Earlier turns are preserved in a compaction checkpoint. Open session checkpoints to branch or restore that pre-compaction view.",
471+);
472+const action = requireRecord(divider.action);
473+expect(action.kind).toBe("session-checkpoints");
474+expect(action.label).toBe("Open checkpoints");
473475});
474476});
475477此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。