Files
oh-my-opencode/src/hooks/claude-code-hooks/transcript.test.ts
T

181 lines
4.5 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, mock, beforeEach, afterEach } from "bun:test"
import { existsSync, unlinkSync, readFileSync } from "fs"
import {
buildTranscriptFromSession,
deleteTempTranscript,
clearTranscriptCache,
} from "./transcript"
function createMockClient(messages: unknown[] = []) {
return {
session: {
messages: mock(() =>
Promise.resolve({
data: messages,
})
),
},
}
}
describe("transcript caching", () => {
afterEach(() => {
clearTranscriptCache()
})
// #given same session called twice
// #when buildTranscriptFromSession is invoked
// #then session.messages() should be called only once (cached)
it("should cache transcript and not re-fetch for same session", async () => {
const client = createMockClient([
{
info: { role: "assistant" },
parts: [
{
type: "tool",
tool: "bash",
state: { status: "completed", input: { command: "ls" } },
},
],
},
])
const path1 = await buildTranscriptFromSession(
client,
"ses_cache1",
"/tmp",
"bash",
{ command: "echo hi" }
)
const path2 = await buildTranscriptFromSession(
client,
"ses_cache1",
"/tmp",
"read",
{ path: "/tmp/file" }
)
// session.messages() called only once
expect(client.session.messages).toHaveBeenCalledTimes(1)
// Both return valid paths
expect(path1).not.toBeNull()
expect(path2).not.toBeNull()
// Second call should append the new tool entry
if (path2) {
const content = readFileSync(path2, "utf-8")
expect(content).toContain("Read")
}
deleteTempTranscript(path1)
deleteTempTranscript(path2)
})
// #given different sessions
// #when buildTranscriptFromSession called for each
// #then session.messages() should be called for each
it("should not share cache between different sessions", async () => {
const client = createMockClient([])
await buildTranscriptFromSession(client, "ses_a", "/tmp", "bash", {})
await buildTranscriptFromSession(client, "ses_b", "/tmp", "bash", {})
expect(client.session.messages).toHaveBeenCalledTimes(2)
clearTranscriptCache()
})
// #given clearTranscriptCache is called
// #when buildTranscriptFromSession called again
// #then should re-fetch
it("should re-fetch after cache is cleared", async () => {
const client = createMockClient([])
await buildTranscriptFromSession(client, "ses_clear", "/tmp", "bash", {})
clearTranscriptCache()
await buildTranscriptFromSession(client, "ses_clear", "/tmp", "bash", {})
expect(client.session.messages).toHaveBeenCalledTimes(2)
})
it("keeps intermediate tool calls across sequential transcript rebuilds", async () => {
// given
const client = createMockClient([])
// when
const firstPath = await buildTranscriptFromSession(
client,
"ses_sequential",
"/tmp",
"bash",
{ command: "echo first" }
)
const secondPath = await buildTranscriptFromSession(
client,
"ses_sequential",
"/tmp",
"read",
{ filePath: "/tmp/second.txt" }
)
const thirdPath = await buildTranscriptFromSession(
client,
"ses_sequential",
"/tmp",
"write",
{ filePath: "/tmp/third.txt", content: "third" }
)
// then
expect(firstPath).not.toBeNull()
expect(secondPath).not.toBeNull()
expect(thirdPath).not.toBeNull()
if (thirdPath) {
const content = readFileSync(thirdPath, "utf-8")
expect(content).toContain("Bash")
expect(content).toContain("Read")
expect(content).toContain("Write")
}
deleteTempTranscript(firstPath)
deleteTempTranscript(secondPath)
deleteTempTranscript(thirdPath)
})
it("cleans up previous temp transcript files when rebuilding cached transcripts", async () => {
// given
const client = createMockClient([])
// when
const firstPath = await buildTranscriptFromSession(
client,
"ses_cleanup",
"/tmp",
"bash",
{ command: "echo first" }
)
const secondPath = await buildTranscriptFromSession(
client,
"ses_cleanup",
"/tmp",
"read",
{ filePath: "/tmp/second.txt" }
)
// then
expect(firstPath).not.toBeNull()
expect(secondPath).not.toBeNull()
if (firstPath && secondPath) {
expect(existsSync(firstPath)).toBe(false)
expect(existsSync(secondPath)).toBe(true)
}
deleteTempTranscript(firstPath)
deleteTempTranscript(secondPath)
})
})