opencode / packages /app /src /pages /session /timeline /projection.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
3e05655 verified
Raw History Blame Contribute Delete
3.62 kB
import { describe, expect, test } from "bun:test"
import type { PartGroup } from "@opencode-ai/session-ui/message-part"
import { reuseTimelineRows } from "./row-reconciliation"
import { TimelineRow } from "./timeline-row"
const context = (key: string, partIDs: string[], userMessageID = "user-1") =>
new TimelineRow.AssistantPart({
userMessageID,
group: {
key,
type: "context",
refs: partIDs.map((partID) => ({ messageID: "assistant-1", partID })),
} satisfies PartGroup,
previousAssistantPart: false,
})
const user = (userMessageID = "user-1") => new TimelineRow.UserMessage({ userMessageID, anchor: true })
const keys = (rows: TimelineRow.TimelineRow[]) => rows.map(TimelineRow.key)
describe("reuseTimelineRows", () => {
test.each([
{
name: "reuses an unchanged context group",
previous: [context("context:a", ["a", "b"])],
rows: [context("context:a", ["a", "b"])],
expected: ["assistant-part:user-1:context:a"],
reused: [[0, 0]],
},
{
name: "preserves the group key when a member is appended",
previous: [context("context:a", ["a"])],
rows: [context("context:a", ["a", "b"])],
expected: ["assistant-part:user-1:context:a"],
reused: [],
},
{
name: "preserves the group key when the first member is removed",
previous: [context("context:a", ["a", "b"])],
rows: [context("context:b", ["b"])],
expected: ["assistant-part:user-1:context:a"],
reused: [],
},
{
name: "lets only the natural owner retain an old key after a split",
previous: [context("context:a", ["a", "b"])],
rows: [context("context:a", ["a"]), context("context:b", ["b"])],
expected: ["assistant-part:user-1:context:a", "assistant-part:user-1:context:b"],
reused: [],
},
{
name: "chooses the earliest prior key when groups merge",
previous: [context("context:a", ["a"]), context("context:b", ["b"])],
rows: [context("context:b", ["b", "a"])],
expected: ["assistant-part:user-1:context:a"],
reused: [],
},
{
name: "reserves an old key for its natural owner when two new groups compete",
previous: [context("context:a", ["a", "b"])],
rows: [context("context:b", ["b"]), context("context:a", ["a"])],
expected: ["assistant-part:user-1:context:b", "assistant-part:user-1:context:a"],
reused: [],
},
{
name: "does not reuse context identity across user messages",
previous: [context("context:a", ["a", "b"], "user-1")],
rows: [context("context:b", ["b"], "user-2")],
expected: ["assistant-part:user-2:context:b"],
reused: [],
},
{
name: "reuses an unaffected ordinary row",
previous: [user()],
rows: [user()],
expected: ["user-message:user-1"],
reused: [[0, 0]],
},
{
name: "does not create accidental key collisions",
previous: [context("context:a", ["a", "b", "c"])],
rows: [context("context:b", ["b"]), context("context:a", ["a"]), context("context:c", ["c"])],
expected: [
"assistant-part:user-1:context:b",
"assistant-part:user-1:context:a",
"assistant-part:user-1:context:c",
],
reused: [],
},
])("$name", ({ previous, rows, expected, reused }) => {
const result = reuseTimelineRows([...previous], [...rows])
expect(keys(result)).toEqual([...expected])
expect(new Set(keys(result)).size).toBe(result.length)
reused.forEach(([resultIndex, previousIndex]) => expect(result[resultIndex]).toBe(previous[previousIndex]))
})
})