test(hooks): update multiple hook test suites
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -4,35 +4,31 @@ const replaceEmptyTextPartsAsync = mock(() => Promise.resolve(false))
|
||||
const injectTextPartAsync = mock(() => Promise.resolve(false))
|
||||
const findMessagesWithEmptyTextPartsFromSDK = mock(() => Promise.resolve([] as string[]))
|
||||
|
||||
async function importFreshMessageBuilder(): Promise<typeof import("./message-builder")> {
|
||||
mock.module("../../shared/logger", () => ({
|
||||
log: () => {},
|
||||
}))
|
||||
mock.module("../../shared/logger", () => ({
|
||||
log: () => {},
|
||||
}))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
}))
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
}))
|
||||
|
||||
const emptyTextMockFactory = () => ({
|
||||
findMessagesWithEmptyTextParts: () => [],
|
||||
replaceEmptyTextParts: () => false,
|
||||
replaceEmptyTextPartsAsync,
|
||||
findMessagesWithEmptyTextPartsFromSDK,
|
||||
})
|
||||
mock.module("../session-recovery/storage/empty-text", emptyTextMockFactory)
|
||||
mock.module("../session-recovery/storage/empty-text.ts", emptyTextMockFactory)
|
||||
const emptyTextMockFactory = () => ({
|
||||
findMessagesWithEmptyTextParts: () => [],
|
||||
replaceEmptyTextParts: () => false,
|
||||
replaceEmptyTextPartsAsync,
|
||||
findMessagesWithEmptyTextPartsFromSDK,
|
||||
})
|
||||
mock.module("../session-recovery/storage/empty-text", emptyTextMockFactory)
|
||||
mock.module("../session-recovery/storage/empty-text.ts", emptyTextMockFactory)
|
||||
|
||||
const textPartInjectorMockFactory = () => ({
|
||||
injectTextPart: () => false,
|
||||
injectTextPartAsync,
|
||||
})
|
||||
mock.module("../session-recovery/storage/text-part-injector", textPartInjectorMockFactory)
|
||||
mock.module("../session-recovery/storage/text-part-injector.ts", textPartInjectorMockFactory)
|
||||
const textPartInjectorMockFactory = () => ({
|
||||
injectTextPart: () => false,
|
||||
injectTextPartAsync,
|
||||
})
|
||||
mock.module("../session-recovery/storage/text-part-injector", textPartInjectorMockFactory)
|
||||
mock.module("../session-recovery/storage/text-part-injector.ts", textPartInjectorMockFactory)
|
||||
|
||||
const module = await import(`./message-builder?test=${Date.now()}-${Math.random()}`)
|
||||
mock.restore()
|
||||
return module
|
||||
}
|
||||
const messageBuilderModulePromise = import("./message-builder")
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
@@ -49,7 +45,7 @@ describe("sanitizeEmptyMessagesBeforeSummarize", () => {
|
||||
})
|
||||
|
||||
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 { sanitizeEmptyMessagesBeforeSummarize, PLACEHOLDER_TEXT } = await messageBuilderModulePromise
|
||||
const client = {
|
||||
session: {
|
||||
messages: mock(() => Promise.resolve({
|
||||
@@ -76,7 +72,7 @@ describe("sanitizeEmptyMessagesBeforeSummarize", () => {
|
||||
})
|
||||
|
||||
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 { sanitizeEmptyMessagesBeforeSummarize, PLACEHOLDER_TEXT } = await messageBuilderModulePromise
|
||||
const client = {
|
||||
session: {
|
||||
messages: mock(() => Promise.resolve({
|
||||
|
||||
@@ -1,45 +1,52 @@
|
||||
import { describe, test, expect, mock, beforeEach, afterAll } from "bun:test"
|
||||
import { truncateUntilTargetTokens } from "./storage"
|
||||
import * as storage from "./storage"
|
||||
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import type { ToolResultInfo } from "./tool-part-types"
|
||||
|
||||
// Mock the entire module
|
||||
mock.module("./storage", () => {
|
||||
return {
|
||||
...storage,
|
||||
findToolResultsBySize: mock(() => []),
|
||||
truncateToolResult: mock(() => ({ success: false })),
|
||||
}
|
||||
})
|
||||
type TruncateToolResult = {
|
||||
success: boolean
|
||||
toolName?: string
|
||||
originalSize?: number
|
||||
}
|
||||
|
||||
const findToolResultsBySize = mock<(_: string) => ToolResultInfo[]>(() => [])
|
||||
const truncateToolResult = mock<(_: string) => TruncateToolResult>(() => ({ success: false }))
|
||||
|
||||
mock.module("./tool-result-storage", () => ({
|
||||
findToolResultsBySize,
|
||||
truncateToolResult,
|
||||
}))
|
||||
|
||||
async function importFreshStorage(): Promise<typeof import("./storage")> {
|
||||
return import(`./storage?test=${Date.now()}-${Math.random()}`)
|
||||
}
|
||||
|
||||
afterAll(() => {
|
||||
mock.module("./storage", () => storage)
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
describe("truncateUntilTargetTokens", () => {
|
||||
const sessionID = "test-session"
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks
|
||||
const { findToolResultsBySize, truncateToolResult } = require("./storage")
|
||||
findToolResultsBySize.mockReset()
|
||||
truncateToolResult.mockReset()
|
||||
findToolResultsBySize.mockReturnValue([])
|
||||
truncateToolResult.mockReturnValue({ success: false })
|
||||
})
|
||||
|
||||
test("truncates only until target is reached", async () => {
|
||||
const { findToolResultsBySize, truncateToolResult } = require("./storage")
|
||||
|
||||
const { truncateUntilTargetTokens } = await importFreshStorage()
|
||||
|
||||
// given: Two tool results, each 1000 chars. Target reduction is 500 chars.
|
||||
const results = [
|
||||
{ partPath: "path1", partId: "id1", messageID: "m1", toolName: "tool1", outputSize: 1000 },
|
||||
{ partPath: "path2", partId: "id2", messageID: "m2", toolName: "tool2", outputSize: 1000 },
|
||||
]
|
||||
|
||||
|
||||
findToolResultsBySize.mockReturnValue(results)
|
||||
truncateToolResult.mockImplementation((path: string) => ({
|
||||
success: true,
|
||||
toolName: path === "path1" ? "tool1" : "tool2",
|
||||
originalSize: 1000
|
||||
originalSize: 1000,
|
||||
}))
|
||||
|
||||
// when: currentTokens=1000, maxTokens=1000, targetRatio=0.5 (target=500, reduce=500)
|
||||
@@ -55,19 +62,19 @@ describe("truncateUntilTargetTokens", () => {
|
||||
})
|
||||
|
||||
test("truncates all if target not reached", async () => {
|
||||
const { findToolResultsBySize, truncateToolResult } = require("./storage")
|
||||
|
||||
const { truncateUntilTargetTokens } = await importFreshStorage()
|
||||
|
||||
// given: Two tool results, each 100 chars. Target reduction is 500 chars.
|
||||
const results = [
|
||||
{ partPath: "path1", partId: "id1", messageID: "m1", toolName: "tool1", outputSize: 100 },
|
||||
{ partPath: "path2", partId: "id2", messageID: "m2", toolName: "tool2", outputSize: 100 },
|
||||
]
|
||||
|
||||
|
||||
findToolResultsBySize.mockReturnValue(results)
|
||||
truncateToolResult.mockImplementation((path: string) => ({
|
||||
success: true,
|
||||
toolName: path === "path1" ? "tool1" : "tool2",
|
||||
originalSize: 100
|
||||
originalSize: 100,
|
||||
}))
|
||||
|
||||
// when: reduce 500 chars
|
||||
|
||||
Reference in New Issue
Block a user