test: make unsafe test coercion explicit

Move test coercion out of a hidden global and require each test to import the helper so review tools and runtime scripts can see the unsafe boundary.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-12 15:38:31 +09:00
parent ce5da13fc5
commit d5fbada13d
103 changed files with 700 additions and 554 deletions
@@ -6,6 +6,7 @@ import { describe, expect, mock, test } from "bun:test"
import type { BackgroundManager } from "../../features/background-agent"
import { clearPendingStore, consumeToolMetadata } from "../../features/tool-metadata-store"
import { createBackgroundTask } from "./create-background-task"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
@@ -18,7 +19,7 @@ describe("createBackgroundTask metadata", () => {
// #given
clearPendingStore()
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
launch: mock(() => Promise.resolve({
id: "task-1",
sessionID: null,
@@ -28,7 +29,7 @@ describe("createBackgroundTask metadata", () => {
})),
getTask: mock(() => undefined),
})
const client = testCoerce<PluginInput["client"]>({
const client = unsafeTestValue<PluginInput["client"]>({
session: {
messages: mock(() => Promise.resolve({ data: [] })),
},
@@ -4,6 +4,7 @@ import { describe, test, expect, mock } from "bun:test"
import type { BackgroundManager } from "../../features/background-agent"
import type { PluginInput } from "@opencode-ai/plugin"
import { createBackgroundTask } from "./create-background-task"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("createBackgroundTask", () => {
const launchMock = mock(async (): Promise<{
@@ -21,12 +22,12 @@ describe("createBackgroundTask", () => {
}))
const getTaskMock = mock()
const mockManager = testCoerce<BackgroundManager>({
const mockManager = unsafeTestValue<BackgroundManager>({
launch: launchMock,
getTask: getTaskMock,
})
const mockClient = testCoerce<PluginInput["client"]>({
const mockClient = unsafeTestValue<PluginInput["client"]>({
session: {
messages: mock(() => Promise.resolve({ data: [] })),
},
+8 -7
View File
@@ -6,6 +6,7 @@ import type { BackgroundManager, BackgroundTask } from "../../features/backgroun
import type { ToolContext } from "@opencode-ai/plugin/tool"
import type { BackgroundCancelClient, BackgroundOutputManager, BackgroundOutputClient } from "./tools"
import { consumeToolMetadata, clearPendingStore } from "../../features/tool-metadata-store"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
@@ -66,7 +67,7 @@ describe("background_output full_session", () => {
const manager = createMockManager(task)
const client = createMockClient({})
const tool = createBackgroundOutput(manager, client)
const ctxWithCallId = testCoerce<ToolContext>({
const ctxWithCallId = unsafeTestValue<ToolContext>({
...mockContext,
callID: "call-1",
})
@@ -93,7 +94,7 @@ describe("background_output full_session", () => {
const manager = createMockManager(task)
const client = createMockClient({})
const tool = createBackgroundOutput(manager, client)
const ctxWithCallId = testCoerce<ToolContext>({
const ctxWithCallId = unsafeTestValue<ToolContext>({
...mockContext,
callID: "call-1",
})
@@ -387,7 +388,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ status: "running" })
const cancelled: string[] = []
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string) => {
@@ -412,7 +413,7 @@ describe("background_cancel", () => {
const taskA = createTask({ id: "task-a", status: "running" })
const taskB = createTask({ id: "task-b", status: "pending" })
const cancelled: string[] = []
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
getTask: () => undefined,
getAllDescendantTasks: () => [taskA, taskB],
cancelTask: async (taskId: string) => {
@@ -437,7 +438,7 @@ describe("background_cancel", () => {
// #given
const taskA = createTask({ id: "task-a", status: "running", sessionId: "ses-a", description: "running task" })
const taskB = createTask({ id: "task-b", status: "pending", sessionId: undefined, description: "pending task" })
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
getTask: () => undefined,
getAllDescendantTasks: () => [taskA, taskB],
cancelTask: async (taskId: string) => {
@@ -461,7 +462,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ id: "task-1", status: "running" })
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string, options?: unknown) => {
@@ -487,7 +488,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ id: "task-1", status: "running" })
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
const manager = testCoerce<BackgroundManager>({
const manager = unsafeTestValue<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string, options?: unknown) => {
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
import { createOrGetSession } from "./session-creator"
import { _resetForTesting, subagentSessions } from "../../features/claude-code-session-state"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("call-omo-agent createOrGetSession", () => {
test("creates child session without overriding permission and tracks it as subagent session", async () => {
@@ -37,12 +38,12 @@ describe("call-omo-agent createOrGetSession", () => {
}
// when
const result = await createOrGetSession(testCoerce(args), testCoerce(toolContext), testCoerce(ctx))
const result = await createOrGetSession(unsafeTestValue(args), unsafeTestValue(toolContext), unsafeTestValue(ctx))
// then
expect(result).toEqual({ sessionID: "ses_child", isNew: true })
expect(createCalls).toHaveLength(1)
const createBody = (testCoerce(createCalls[0]))?.body
const createBody = (unsafeTestValue(createCalls[0]))?.body
expect(createBody?.parentID).toBe("ses_parent")
expect(createBody?.permission).toBeUndefined()
expect(subagentSessions.has("ses_child")).toBe(true)
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
import { resolveOrCreateSessionId } from "./subagent-session-creator"
import { _resetForTesting, subagentSessions } from "../../features/claude-code-session-state"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("call-omo-agent resolveOrCreateSessionId", () => {
const originalPlatform = process.platform
@@ -19,7 +20,7 @@ describe("call-omo-agent resolveOrCreateSessionId", () => {
const { parentDirectory, contextDirectory } = options
const parentSessionData = parentDirectory ? { data: { directory: parentDirectory } } : { data: {} }
const ctx = testCoerce<Parameters<typeof resolveOrCreateSessionId>[0]>({
const ctx = unsafeTestValue<Parameters<typeof resolveOrCreateSessionId>[0]>({
directory: contextDirectory,
client: {
session: {
@@ -1,3 +1,4 @@
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const { describe, test, expect, mock } = require("bun:test")
type ExecuteSync = typeof import("./sync-executor").executeSync
@@ -389,7 +390,7 @@ describe("executeSync", () => {
}
//#when
await executeSync(args, toolContext, testCoerce(ctx), deps, undefined, spawnReservation)
await executeSync(args, toolContext, unsafeTestValue(ctx), deps, undefined, spawnReservation)
//#then
expect(spawnReservation.commit).toHaveBeenCalledTimes(1)
@@ -3,6 +3,7 @@ const { describe, test, expect, beforeEach, afterEach, spyOn, mock } = require("
import { resolveCategoryExecution } from "./category-resolver"
import type { ExecutorContext } from "./executor-types"
import * as connectedProvidersCache from "../../shared/connected-providers-cache"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("resolveCategoryExecution", () => {
let connectedProvidersSpy: ReturnType<typeof spyOn> | undefined
@@ -26,8 +27,8 @@ describe("resolveCategoryExecution", () => {
})
const createMockExecutorContext = (): ExecutorContext => ({
client: testCoerce({}),
manager: testCoerce({}),
client: unsafeTestValue({}),
manager: unsafeTestValue({}),
directory: "/tmp/test",
userCategories: {},
sisyphusJuniorModel: undefined,
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
import { executeBackgroundTask } from "./executor"
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("task tool metadata awaiting", () => {
test("executeBackgroundTask awaits ctx.metadata before returning", async () => {
@@ -28,7 +29,7 @@ describe("task tool metadata awaiting", () => {
subagent_type: "explore",
}
const executorCtx = testCoerce({
const executorCtx = unsafeTestValue({
manager: {
launch: async () => ({
id: "task_1",
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
import type { ParentContext } from "./executor-types"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
const MODEL_WITH_VARIANT = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" }
@@ -63,7 +64,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, testCoerce({
await executeBackgroundTask(args, ctx, unsafeTestValue({
manager: {
launch: async () => ({
id: "bg_1", description: "test", agent: "explore",
@@ -92,7 +93,7 @@ describe("metadata model unification", () => {
}
await executeUnstableAgentTask(
args, ctx,
testCoerce({
unsafeTestValue({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -126,7 +127,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_2", description: "continue", agent: "explore",
@@ -153,7 +154,7 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -206,7 +207,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, testCoerce({
await executeBackgroundTask(args, ctx, unsafeTestValue({
manager: {
launch: async () => ({
id: "bg_1", description: "test", agent: "explore",
@@ -236,7 +237,7 @@ describe("metadata model unification", () => {
await executeUnstableAgentTask(
args, ctx,
testCoerce({
unsafeTestValue({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -270,7 +271,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_2", description: "continue", agent: "explore",
@@ -297,7 +298,7 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({ data: [] }),
@@ -381,7 +382,7 @@ describe("metadata model unification", () => {
category: "visual-engineering", load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, testCoerce({
await executeBackgroundTask(args, ctx, unsafeTestValue({
manager: {
launch: async () => ({
id: "bg_variant", description: "test", agent: "explore",
@@ -411,7 +412,7 @@ describe("metadata model unification", () => {
await executeUnstableAgentTask(
args, ctx,
testCoerce({
unsafeTestValue({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -445,7 +446,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_variant",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_resume_variant", description: "continue", agent: "explore",
@@ -472,7 +473,7 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
import type { ParentContext } from "./executor-types"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
@@ -64,7 +65,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, testCoerce({
await executeBackgroundTask(args, ctx, unsafeTestValue({
manager: {
launch: async () => ({
id: "bg_abc123", description: "test", agent: "explore",
@@ -98,7 +99,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
await executeUnstableAgentTask(
args, ctx,
testCoerce({
unsafeTestValue({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -136,7 +137,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
@@ -160,7 +161,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
@@ -187,7 +188,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
@@ -216,7 +217,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -246,7 +247,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -275,7 +276,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -309,7 +310,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -368,7 +369,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
run_in_background: true,
}
await executeBackgroundTask(args, ctx, testCoerce({
await executeBackgroundTask(args, ctx, unsafeTestValue({
manager: {
launch: async () => ({
id: "bg_abc123", description: "test", agent: "Sisyphus-Junior",
@@ -402,7 +403,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
await executeUnstableAgentTask(
args, ctx,
testCoerce({
unsafeTestValue({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -438,7 +439,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resume_title",
}
await executeBackgroundContinuation(args, ctx, testCoerce({
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
manager: {
resume: async () => ({
id: "bg_resume_title", description: "continue work", agent: "explore",
@@ -460,7 +461,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: false, task_id: "ses_sync_title",
}
await executeSyncContinuation(args, ctx, testCoerce({
await executeSyncContinuation(args, ctx, unsafeTestValue({
client: {
session: {
messages: async () => ({
@@ -500,8 +501,8 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
},
}
const bgOutput = createBackgroundOutput(testCoerce(manager), testCoerce(client))
await bgOutput.execute(testCoerce({ task_id: "bg_output_xyz" }), testCoerce(ctx))
const bgOutput = createBackgroundOutput(unsafeTestValue(manager), unsafeTestValue(client))
await bgOutput.execute(unsafeTestValue({ task_id: "bg_output_xyz" }), unsafeTestValue(ctx))
const meta = ctx.captured.find((m: any) => m.metadata?.backgroundTaskId)
expect(meta).toBeDefined()
+2 -1
View File
@@ -1,3 +1,4 @@
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const { describe, expect, test } = require("bun:test")
function requireFresh<T>(modulePath: string): T {
@@ -18,7 +19,7 @@ function createDelegateTask(...args: Parameters<typeof import("./tools").createD
const toolDefinition = createDelegateTask({ manager: {} as never, client: {} as never, directory: "/tmp/test" })
//#when
const categorySchema = testCoerce<{
const categorySchema = unsafeTestValue<{
def: {
type: string
innerType: {
@@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"
import { executeUnstableAgentTask } from "./unstable-agent-task"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("executeUnstableAgentTask session permission", () => {
test("passes question-deny session permission into background launch", async () => {
@@ -33,7 +34,7 @@ describe("executeUnstableAgentTask session permission", () => {
metadata: () => {},
abort: new AbortController().signal,
} satisfies Parameters<typeof executeUnstableAgentTask>[1]
const executorContext = testCoerce<Parameters<typeof executeUnstableAgentTask>[2]>({
const executorContext = unsafeTestValue<Parameters<typeof executeUnstableAgentTask>[2]>({
manager: mockManager,
client: {
session: {
@@ -1,5 +1,6 @@
import { describe, expect, it } from "bun:test"
import { normalizeHashlineEdits, type RawHashlineEdit } from "./normalize-edits"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("normalizeHashlineEdits", () => {
it("maps replace with pos to replace", () => {
@@ -51,7 +52,7 @@ describe("normalizeHashlineEdits", () => {
it("rejects legacy payload without op", () => {
//#given
const input = testCoerce<Parameters<
const input = unsafeTestValue<Parameters<
typeof normalizeHashlineEdits
>[0]>([{ type: "set_line", line: "2#VK", text: "updated" }])
+2 -1
View File
@@ -6,9 +6,10 @@ import { canonicalizeFileText } from "./file-text-canonicalization"
import * as fs from "node:fs"
import * as os from "node:os"
import * as path from "node:path"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
function createMockContext(): ToolContext {
return testCoerce<ToolContext>({
return unsafeTestValue<ToolContext>({
sessionID: "test",
messageID: "test",
agent: "test",
@@ -6,6 +6,7 @@ import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadat
import { setVisionCapableModelsCache, clearVisionCapableModelsCache } from "../../shared/vision-capable-models-cache"
import * as connectedProvidersCache from "../../shared/connected-providers-cache"
import * as modelAvailability from "../../shared/model-availability"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
function createPluginInput(agentData: Array<Record<string, unknown>>): PluginInput {
const client = {} as PluginInput["client"]
@@ -32,8 +33,8 @@ describe("resolveMultimodalLookerAgentMetadata", () => {
afterEach(() => {
clearVisionCapableModelsCache()
;(testCoerce<{ mockRestore?: () => void }>(modelAvailability.fetchAvailableModels)).mockRestore?.()
;(testCoerce<{ mockRestore?: () => void }>(connectedProvidersCache.readConnectedProvidersCache)).mockRestore?.()
;(unsafeTestValue<{ mockRestore?: () => void }>(modelAvailability.fetchAvailableModels)).mockRestore?.()
;(unsafeTestValue<{ mockRestore?: () => void }>(connectedProvidersCache.readConnectedProvidersCache)).mockRestore?.()
})
test("returns configured multimodal-looker model when it already matches a vision-capable override", async () => {
+7 -6
View File
@@ -1,5 +1,6 @@
import { describe, expect, test, mock } from "bun:test"
import { pollSessionUntilIdle } from "./session-poller"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
type SessionStatusResult = {
data?: Record<string, { type: string; attempt?: number; message?: string; next?: number }>
@@ -30,7 +31,7 @@ describe("pollSessionUntilIdle", () => {
{ data: { ses_test: { type: "idle" } } },
])
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(3)
})
@@ -43,7 +44,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(1)
})
@@ -57,7 +58,7 @@ describe("pollSessionUntilIdle", () => {
])
await expect(
pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
).rejects.toThrow("timed out")
})
@@ -69,7 +70,7 @@ describe("pollSessionUntilIdle", () => {
{ error: new Error("API error") },
])
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(1)
})
@@ -85,7 +86,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(4)
})
@@ -98,7 +99,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(testCoerce(client), "ses_test")
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test")
expect(client.session.status).toHaveBeenCalledTimes(1)
})
+21 -20
View File
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test, mock } from "bun:test"
import type { ToolContext } from "@opencode-ai/plugin/tool"
import { clearVisionCapableModelsCache, setVisionCapableModelsCache } from "../../shared/vision-capable-models-cache"
import { normalizeArgs, validateArgs, createLookAt } from "./tools"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("look-at tool", () => {
afterEach(() => {
@@ -14,7 +15,7 @@ describe("look-at tool", () => {
// then should normalize to file_path
test("normalizes path to file_path for LLM compatibility", () => {
const args = { path: "/some/file.png", goal: "analyze" }
const normalized = normalizeArgs(testCoerce(args))
const normalized = normalizeArgs(unsafeTestValue(args))
expect(normalized.file_path).toBe("/some/file.png")
expect(normalized.goal).toBe("analyze")
})
@@ -33,7 +34,7 @@ describe("look-at tool", () => {
// then prefer file_path
test("prefers file_path over path when both provided", () => {
const args = { file_path: "/preferred.png", path: "/fallback.png", goal: "test" }
const normalized = normalizeArgs(testCoerce(args))
const normalized = normalizeArgs(unsafeTestValue(args))
expect(normalized.file_path).toBe("/preferred.png")
})
@@ -42,7 +43,7 @@ describe("look-at tool", () => {
// then preserve image_data in normalized args
test("preserves image_data when provided", () => {
const args = { image_data: "data:image/png;base64,iVBORw0KGgo=", goal: "analyze" }
const normalized = normalizeArgs(testCoerce(args))
const normalized = normalizeArgs(unsafeTestValue(args))
expect(normalized.image_data).toBe("data:image/png;base64,iVBORw0KGgo=")
expect(normalized.file_path).toBeUndefined()
})
@@ -69,7 +70,7 @@ describe("look-at tool", () => {
// when validated
// then clear error message
test("returns error when neither file_path nor image_data provided", () => {
const args = testCoerce({ goal: "analyze" })
const args = unsafeTestValue({ goal: "analyze" })
const error = validateArgs(args)
expect(error).toContain("file_path")
expect(error).toContain("image_data")
@@ -88,7 +89,7 @@ describe("look-at tool", () => {
// when validated
// then clear error message
test("returns error when goal is missing", () => {
const args = testCoerce({ file_path: "/some/path.png" })
const args = unsafeTestValue({ file_path: "/some/path.png" })
const error = validateArgs(args)
expect(error).toContain("goal")
expect(error).toContain("required")
@@ -156,7 +157,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -193,7 +194,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -230,7 +231,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -291,7 +292,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -346,7 +347,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -395,7 +396,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -437,7 +438,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -486,7 +487,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -515,7 +516,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -539,7 +540,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -579,7 +580,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -632,7 +633,7 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -701,7 +702,7 @@ describe("look-at tool", () => {
test("instructs agent to analyze attached file when Read is disabled (file_path mode)", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -726,7 +727,7 @@ describe("look-at tool", () => {
test("instructs agent to analyze attached image when image_data is provided", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
@@ -751,7 +752,7 @@ describe("look-at tool", () => {
test("explicitly warns the agent not to attempt Read when Read is disabled", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt(testCoerce({
const tool = createLookAt(unsafeTestValue({
client: mockClient,
directory: "/project",
}))
+3 -2
View File
@@ -16,6 +16,7 @@ afterAll(() => { mock.restore() })
import { LSPClient, lspManager, validateCwd } from "./client"
import type { ResolvedServer } from "./types"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("LSPClient", () => {
beforeEach(async () => {
@@ -36,7 +37,7 @@ describe("LSPClient", () => {
const originalSetTimeout = globalThis.setTimeout
globalThis.setTimeout = ((fn: (...args: unknown[]) => void, _ms?: number) => {
fn()
return testCoerce<ReturnType<typeof setTimeout>>(0)
return unsafeTestValue<ReturnType<typeof setTimeout>>(0)
}) as typeof setTimeout
const server: ResolvedServer = {
@@ -50,7 +51,7 @@ describe("LSPClient", () => {
// Stub protocol output: we only want to assert notifications.
const sendNotificationSpy = spyOn(
testCoerce<{ sendNotification: (m: string, p?: unknown) => void }>(client),
unsafeTestValue<{ sendNotification: (m: string, p?: unknown) => void }>(client),
"sendNotification"
)
+6 -5
View File
@@ -3,6 +3,7 @@ import { mkdirSync, writeFileSync, rmSync, existsSync, readdirSync } from "node:
import { join } from "node:path"
import { tmpdir } from "node:os"
import { randomUUID } from "node:crypto"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
const TEST_DIR = join(tmpdir(), `omo-test-session-manager-${randomUUID()}`)
const TEST_MESSAGE_STORAGE = join(TEST_DIR, "message")
@@ -448,7 +449,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
// Re-import to get fresh module with mocked isSqliteBackend
const { setStorageClient, getMainSessions } = await import("./storage")
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const sessions = await getMainSessions({ directory: "/test" })
@@ -473,7 +474,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, getAllSessions } = await import("./storage")
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const sessionIDs = await getAllSessions()
@@ -503,7 +504,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionMessages } = await import("./storage")
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const messages = await readSessionMessages("ses_test")
@@ -531,7 +532,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionTodos } = await import("./storage")
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const todos = await readSessionTodos("ses_test")
@@ -555,7 +556,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionMessages } = await import("./storage")
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
await expect(readSessionMessages("ses_test")).rejects.toThrow("API error")
})
@@ -12,6 +12,7 @@ import { clearSkillCache } from "../../../features/opencode-skill-loader/skill-c
import type { LoadedSkill } from "../../../features/opencode-skill-loader/types"
import type { CommandInfo } from "../../slashcommand/types"
import type { Tool as McpTool } from "@modelcontextprotocol/sdk/types.js"
import { unsafeTestValue } from "../../../../test-support/unsafe-test-value"
const originalReadFileSync = fs.readFileSync.bind(fs)
@@ -205,7 +206,7 @@ describe("skill tool - agent restriction", () => {
// given
const loadedSkills = [createMockSkill("sisyphus-only-skill", { agent: "sisyphus" })]
const tool = createSkillTool({ skills: loadedSkills })
const contextWithoutAgent = { ...mockContext, agent: testCoerce<string>(undefined) }
const contextWithoutAgent = { ...mockContext, agent: unsafeTestValue<string>(undefined) }
// when / #then
return expect(tool.execute({ name: "sisyphus-only-skill" }, contextWithoutAgent)).rejects.toThrow(