Files
oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/message-builder.test.ts
T
YeonGyu-Kim 382f9b61fa Fix mock isolation in remaining hook tests
- message-builder.test.ts: improve mock isolation
- background-update-check.ts: update for test compatibility
- execute-http-hook-security.test.ts: narrow mock targets
- recover-tool-result-missing.test.ts: prevent barrel contamination

🤖 GENERATED WITH ASSISTANCE OF OhMyOpenCode
2026-04-04 18:56:34 +09:00

108 lines
3.6 KiB
TypeScript

import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test"
const replaceEmptyTextPartsAsync = mock(() => Promise.resolve(false))
const injectTextPartAsync = mock(() => Promise.resolve(false))
const findMessagesWithEmptyTextPartsFromSDK = mock(() => Promise.resolve([] as string[]))
mock.module("../../shared/normalize-sdk-response", () => ({
normalizeSDKResponse: (response: { data?: unknown[] }) => response.data ?? [],
}))
mock.module("../../shared/logger", () => ({
log: () => {},
}))
mock.module("../../shared/opencode-storage-detection", () => ({
isSqliteBackend: () => true,
}))
mock.module("../session-recovery/storage", () => ({
findEmptyMessages: () => [],
findMessagesWithEmptyTextParts: () => [],
injectTextPart: () => false,
replaceEmptyTextParts: () => false,
}))
mock.module("../session-recovery/storage/empty-text", () => ({
replaceEmptyTextPartsAsync,
findMessagesWithEmptyTextPartsFromSDK,
}))
mock.module("../session-recovery/storage/text-part-injector", () => ({
injectTextPartAsync,
}))
async function importFreshMessageBuilder(): Promise<typeof import("./message-builder")> {
const module = await import(`./message-builder?test=${Date.now()}-${Math.random()}`)
mock.restore()
return module
}
afterAll(() => {
mock.restore()
})
describe("sanitizeEmptyMessagesBeforeSummarize", () => {
beforeEach(() => {
replaceEmptyTextPartsAsync.mockReset()
replaceEmptyTextPartsAsync.mockResolvedValue(false)
injectTextPartAsync.mockReset()
injectTextPartAsync.mockResolvedValue(false)
findMessagesWithEmptyTextPartsFromSDK.mockReset()
findMessagesWithEmptyTextPartsFromSDK.mockResolvedValue([])
})
test("#given sqlite message with tool content and empty text part #when sanitizing #then it fixes the mixed-content message", async () => {
const { sanitizeEmptyMessagesBeforeSummarize, PLACEHOLDER_TEXT } = await importFreshMessageBuilder()
const client = {
session: {
messages: mock(() => Promise.resolve({
data: [
{
info: { id: "msg-1" },
parts: [
{ type: "tool_result", text: "done" },
{ type: "text", text: "" },
],
},
],
})),
},
} as never
findMessagesWithEmptyTextPartsFromSDK.mockResolvedValue(["msg-1"])
replaceEmptyTextPartsAsync.mockResolvedValue(true)
const fixedCount = await sanitizeEmptyMessagesBeforeSummarize("ses-1", client)
expect(fixedCount).toBe(1)
expect(replaceEmptyTextPartsAsync).toHaveBeenCalledWith(client, "ses-1", "msg-1", PLACEHOLDER_TEXT)
expect(injectTextPartAsync).not.toHaveBeenCalled()
})
test("#given sqlite message with mixed content and failed replacement #when sanitizing #then it injects the placeholder text part", async () => {
const { sanitizeEmptyMessagesBeforeSummarize, PLACEHOLDER_TEXT } = await importFreshMessageBuilder()
const client = {
session: {
messages: mock(() => Promise.resolve({
data: [
{
info: { id: "msg-2" },
parts: [
{ type: "tool_use", text: "call" },
{ type: "text", text: "" },
],
},
],
})),
},
} as never
findMessagesWithEmptyTextPartsFromSDK.mockResolvedValue(["msg-2"])
injectTextPartAsync.mockResolvedValue(true)
const fixedCount = await sanitizeEmptyMessagesBeforeSummarize("ses-2", client)
expect(fixedCount).toBe(1)
expect(injectTextPartAsync).toHaveBeenCalledWith(client, "ses-2", "msg-2", PLACEHOLDER_TEXT)
})
})