fix: correct test type casts, timeouts, and mock structures
- Fix PluginInput type casts to use 'as unknown as PluginInput' - Add explicit TodoSnapshot type annotations - Add timeouts to slow todo-continuation-enforcer tests - Remove unnecessary test storage mocks in atlas and prometheus-md-only - Restructure sync-executor mocks to use beforeEach/afterEach pattern
This commit is contained in:
@@ -1,13 +1,21 @@
|
||||
import { describe, test, expect, mock, beforeEach } from "bun:test"
|
||||
import { describe, test, expect, mock, beforeEach, afterAll } from "bun:test"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { ExperimentalConfig } from "../../config"
|
||||
|
||||
const attemptDeduplicationRecoveryMock = mock(async () => {})
|
||||
const realDeduplicationRecovery = await import("./deduplication-recovery")
|
||||
|
||||
const attemptDeduplicationRecoveryMock = mock<(sessionID: string) => Promise<void>>(
|
||||
async () => {}
|
||||
)
|
||||
|
||||
mock.module("./deduplication-recovery", () => ({
|
||||
attemptDeduplicationRecovery: attemptDeduplicationRecoveryMock,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.module("./deduplication-recovery", () => ({ ...realDeduplicationRecovery }))
|
||||
})
|
||||
|
||||
function createImmediateTimeouts(): () => void {
|
||||
const originalSetTimeout = globalThis.setTimeout
|
||||
const originalClearTimeout = globalThis.clearTimeout
|
||||
@@ -37,13 +45,15 @@ describe("createAnthropicContextWindowLimitRecoveryHook", () => {
|
||||
const experimental = {
|
||||
dynamic_context_pruning: {
|
||||
enabled: true,
|
||||
notification: "off",
|
||||
protected_tools: [],
|
||||
strategies: {
|
||||
deduplication: { enabled: true },
|
||||
},
|
||||
},
|
||||
} satisfies ExperimentalConfig
|
||||
|
||||
let resolveSummarize: (() => void) | null = null
|
||||
let resolveSummarize: ((value?: void) => void) | null = null
|
||||
const summarizePromise = new Promise<void>((resolve) => {
|
||||
resolveSummarize = resolve
|
||||
})
|
||||
@@ -62,7 +72,7 @@ describe("createAnthropicContextWindowLimitRecoveryHook", () => {
|
||||
|
||||
try {
|
||||
const { createAnthropicContextWindowLimitRecoveryHook } = await import("./recovery-hook")
|
||||
const ctx = { client: mockClient, directory: "/tmp" } as PluginInput
|
||||
const ctx = { client: mockClient, directory: "/tmp" } as unknown as PluginInput
|
||||
const hook = createAnthropicContextWindowLimitRecoveryHook(ctx, { experimental })
|
||||
|
||||
// first error triggers compaction (setTimeout runs immediately due to mock)
|
||||
@@ -105,7 +115,7 @@ describe("createAnthropicContextWindowLimitRecoveryHook", () => {
|
||||
}
|
||||
|
||||
const { createAnthropicContextWindowLimitRecoveryHook } = await import("./recovery-hook")
|
||||
const ctx = { client: mockClient, directory: "/tmp" } as PluginInput
|
||||
const ctx = { client: mockClient, directory: "/tmp" } as unknown as PluginInput
|
||||
const hook = createAnthropicContextWindowLimitRecoveryHook(ctx)
|
||||
|
||||
//#when - single error (no compaction in progress)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
|
||||
import { describe, expect, test, beforeEach, afterEach, afterAll, mock } from "bun:test"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -9,20 +9,19 @@ import {
|
||||
readBoulderState,
|
||||
} from "../../features/boulder-state"
|
||||
import type { BoulderState } from "../../features/boulder-state"
|
||||
|
||||
const TEST_STORAGE_ROOT = join(tmpdir(), `atlas-message-storage-${randomUUID()}`)
|
||||
const TEST_MESSAGE_STORAGE = join(TEST_STORAGE_ROOT, "message")
|
||||
const TEST_PART_STORAGE = join(TEST_STORAGE_ROOT, "part")
|
||||
|
||||
mock.module("../../features/hook-message-injector/constants", () => ({
|
||||
OPENCODE_STORAGE: TEST_STORAGE_ROOT,
|
||||
MESSAGE_STORAGE: TEST_MESSAGE_STORAGE,
|
||||
PART_STORAGE: TEST_PART_STORAGE,
|
||||
}))
|
||||
const realClaudeCodeSessionState = await import(
|
||||
"../../features/claude-code-session-state"
|
||||
)
|
||||
|
||||
const { createAtlasHook } = await import("./index")
|
||||
const { MESSAGE_STORAGE } = await import("../../features/hook-message-injector")
|
||||
|
||||
afterAll(() => {
|
||||
mock.module("../../features/claude-code-session-state", () => ({
|
||||
...realClaudeCodeSessionState,
|
||||
}))
|
||||
})
|
||||
|
||||
describe("atlas hook", () => {
|
||||
let TEST_DIR: string
|
||||
let SISYPHUS_DIR: string
|
||||
@@ -77,7 +76,6 @@ describe("atlas hook", () => {
|
||||
if (existsSync(TEST_DIR)) {
|
||||
rmSync(TEST_DIR, { recursive: true, force: true })
|
||||
}
|
||||
rmSync(TEST_STORAGE_ROOT, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
describe("tool.execute.after handler", () => {
|
||||
|
||||
@@ -30,7 +30,7 @@ function createMockContext(todoResponses: TodoSnapshot[][]): PluginInput {
|
||||
},
|
||||
},
|
||||
directory: "/tmp/test",
|
||||
} as PluginInput
|
||||
} as unknown as PluginInput
|
||||
}
|
||||
|
||||
describe("compaction-todo-preserver", () => {
|
||||
@@ -38,7 +38,7 @@ describe("compaction-todo-preserver", () => {
|
||||
//#given
|
||||
updateMock.mockClear()
|
||||
const sessionID = "session-compaction-missing"
|
||||
const todos = [
|
||||
const todos: TodoSnapshot[] = [
|
||||
{ id: "1", content: "Task 1", status: "pending", priority: "high" },
|
||||
{ id: "2", content: "Task 2", status: "in_progress", priority: "medium" },
|
||||
]
|
||||
@@ -58,7 +58,7 @@ describe("compaction-todo-preserver", () => {
|
||||
//#given
|
||||
updateMock.mockClear()
|
||||
const sessionID = "session-compaction-present"
|
||||
const todos = [
|
||||
const todos: TodoSnapshot[] = [
|
||||
{ id: "1", content: "Task 1", status: "pending", priority: "high" },
|
||||
]
|
||||
const ctx = createMockContext([todos, todos])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
|
||||
import { describe, expect, test, beforeEach, afterEach } from "bun:test"
|
||||
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -6,16 +6,6 @@ import { randomUUID } from "node:crypto"
|
||||
import { SYSTEM_DIRECTIVE_PREFIX } from "../../shared/system-directive"
|
||||
import { clearSessionAgent } from "../../features/claude-code-session-state"
|
||||
|
||||
const TEST_STORAGE_ROOT = join(tmpdir(), `prometheus-md-only-${randomUUID()}`)
|
||||
const TEST_MESSAGE_STORAGE = join(TEST_STORAGE_ROOT, "message")
|
||||
const TEST_PART_STORAGE = join(TEST_STORAGE_ROOT, "part")
|
||||
|
||||
mock.module("../../features/hook-message-injector/constants", () => ({
|
||||
OPENCODE_STORAGE: TEST_STORAGE_ROOT,
|
||||
MESSAGE_STORAGE: TEST_MESSAGE_STORAGE,
|
||||
PART_STORAGE: TEST_PART_STORAGE,
|
||||
}))
|
||||
|
||||
const { createPrometheusMdOnlyHook } = await import("./index")
|
||||
const { MESSAGE_STORAGE } = await import("../../features/hook-message-injector")
|
||||
|
||||
@@ -52,7 +42,6 @@ describe("prometheus-md-only", () => {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
rmSync(TEST_STORAGE_ROOT, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
describe("agent name matching", () => {
|
||||
|
||||
@@ -518,7 +518,7 @@ describe("todo-continuation-enforcer", () => {
|
||||
|
||||
//#then
|
||||
expect(promptCalls).toHaveLength(2)
|
||||
})
|
||||
}, 20000)
|
||||
|
||||
test("should keep injecting even when todos remain unchanged across cycles", async () => {
|
||||
//#given
|
||||
@@ -553,7 +553,7 @@ describe("todo-continuation-enforcer", () => {
|
||||
|
||||
//#then — all 5 injections should fire (no stagnation cap)
|
||||
expect(promptCalls).toHaveLength(5)
|
||||
})
|
||||
}, 30000)
|
||||
|
||||
test("should skip idle handling while injection is in flight", async () => {
|
||||
//#given
|
||||
@@ -613,7 +613,7 @@ describe("todo-continuation-enforcer", () => {
|
||||
|
||||
//#then
|
||||
expect(promptCalls).toHaveLength(2)
|
||||
})
|
||||
}, 20000)
|
||||
|
||||
test("should accept skipAgents option without error", async () => {
|
||||
// given - session with skipAgents configured for Prometheus
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
const { describe, test, expect, mock } = require("bun:test")
|
||||
const { describe, test, expect, mock, beforeEach, afterEach } = require("bun:test")
|
||||
|
||||
mock.module("./session-creator", () => ({
|
||||
createOrGetSession: mock(async () => ({ sessionID: "ses-test-123" })),
|
||||
}))
|
||||
const realCompletionPoller = require("./completion-poller")
|
||||
const realMessageProcessor = require("./message-processor")
|
||||
|
||||
mock.module("./completion-poller", () => ({
|
||||
waitForCompletion: mock(async () => {}),
|
||||
}))
|
||||
const waitForCompletionMock = mock(async () => {})
|
||||
const processMessagesMock = mock(async () => "agent response")
|
||||
|
||||
mock.module("./message-processor", () => ({
|
||||
processMessages: mock(async () => "agent response"),
|
||||
}))
|
||||
beforeEach(() => {
|
||||
waitForCompletionMock.mockClear()
|
||||
processMessagesMock.mockClear()
|
||||
|
||||
mock.module("./completion-poller", () => ({
|
||||
waitForCompletion: waitForCompletionMock,
|
||||
}))
|
||||
|
||||
mock.module("./message-processor", () => ({
|
||||
processMessages: processMessagesMock,
|
||||
}))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mock.module("./completion-poller", () => ({ ...realCompletionPoller }))
|
||||
mock.module("./message-processor", () => ({ ...realMessageProcessor }))
|
||||
})
|
||||
|
||||
describe("executeSync", () => {
|
||||
test("passes question=false via tools parameter to block question tool", async () => {
|
||||
@@ -27,6 +39,7 @@ describe("executeSync", () => {
|
||||
subagent_type: "explore",
|
||||
description: "test task",
|
||||
prompt: "find something",
|
||||
session_id: "ses-test-123",
|
||||
}
|
||||
|
||||
const toolContext = {
|
||||
@@ -39,7 +52,10 @@ describe("executeSync", () => {
|
||||
|
||||
const ctx = {
|
||||
client: {
|
||||
session: { promptAsync },
|
||||
session: {
|
||||
promptAsync,
|
||||
get: mock(async () => ({ data: { id: "ses-test-123" } })),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -65,6 +81,7 @@ describe("executeSync", () => {
|
||||
subagent_type: "librarian",
|
||||
description: "search docs",
|
||||
prompt: "find docs",
|
||||
session_id: "ses-test-123",
|
||||
}
|
||||
|
||||
const toolContext = {
|
||||
@@ -77,7 +94,10 @@ describe("executeSync", () => {
|
||||
|
||||
const ctx = {
|
||||
client: {
|
||||
session: { promptAsync },
|
||||
session: {
|
||||
promptAsync,
|
||||
get: mock(async () => ({ data: { id: "ses-test-123" } })),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user