90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|||
|
|
import type { Event, Part } from "@opencode-ai/sdk/v2/client"
|
||
|
|
import { applyDirectoryEvent } from "../event-reducer"
|
||
|
|
import { INITIAL_STATE, type State } from "../types"
|
||
|
|
|
||
|
|
function state(overrides: Partial<State> = {}): State {
|
||
|
|
return {
|
||
|
|
...INITIAL_STATE,
|
||
|
|
message: {},
|
||
|
|
part: {},
|
||
|
|
...overrides,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function deltaEvent(): Event {
|
||
|
|
return {
|
||
|
|
type: "message.part.delta",
|
||
|
|
properties: {
|
||
|
|
messageID: "msg_1",
|
||
|
|
partID: "prt_1",
|
||
|
|
field: "text",
|
||
|
|
delta: "hello",
|
||
|
|
},
|
||
|
|
} as Event
|
||
|
|
}
|
||
|
|
|
||
|
|
function partUpdatedEvent(): Event {
|
||
|
|
return {
|
||
|
|
type: "message.part.updated",
|
||
|
|
properties: {
|
||
|
|
part: {
|
||
|
|
id: "prt_1",
|
||
|
|
messageID: "msg_1",
|
||
|
|
sessionID: "ses_1",
|
||
|
|
type: "text",
|
||
|
|
text: "hello",
|
||
|
|
},
|
||
|
|
},
|
||
|
|
} as Event
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("applyDirectoryEvent", () => {
|
||
|
|
test("returns typed materialization when delta arrives before parts", () => {
|
||
|
|
const result = applyDirectoryEvent(state(), deltaEvent())
|
||
|
|
|
||
|
|
expect(result).toEqual({
|
||
|
|
changed: false,
|
||
|
|
materialization: { type: "incomplete-session-snapshot", messageID: "msg_1", partID: "prt_1" },
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
test("returns typed materialization when delta part is missing", () => {
|
||
|
|
const result = applyDirectoryEvent(
|
||
|
|
state({ part: { msg_1: [{ id: "prt_2", messageID: "msg_1", type: "text", text: "" } as Part] } }),
|
||
|
|
deltaEvent(),
|
||
|
|
)
|
||
|
|
|
||
|
|
expect(result).toEqual({
|
||
|
|
changed: false,
|
||
|
|
materialization: { type: "incomplete-session-snapshot", messageID: "msg_1", partID: "prt_1" },
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
test("applies part update and requests materialization when owning message is absent", () => {
|
||
|
|
const draft = state()
|
||
|
|
const result = applyDirectoryEvent(draft, partUpdatedEvent())
|
||
|
|
|
||
|
|
expect(draft.part.msg_1.map((item) => item.id)).toEqual(["prt_1"])
|
||
|
|
expect(result).toEqual({
|
||
|
|
changed: true,
|
||
|
|
materialization: {
|
||
|
|
type: "incomplete-session-snapshot",
|
||
|
|
sessionID: "ses_1",
|
||
|
|
messageID: "msg_1",
|
||
|
|
partID: "prt_1",
|
||
|
|
},
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
test("applies part update without materialization when owning message exists", () => {
|
||
|
|
const draft = state({
|
||
|
|
message: { ses_1: [{ id: "msg_1", sessionID: "ses_1", role: "assistant", time: { created: 1 } } as never] },
|
||
|
|
})
|
||
|
|
const result = applyDirectoryEvent(draft, partUpdatedEvent())
|
||
|
|
|
||
|
|
expect(draft.part.msg_1.map((item) => item.id)).toEqual(["prt_1"])
|
||
|
|
expect(result).toBe(true)
|
||
|
|
})
|
||
|
|
})
|