From 262472ba207c2f1b0e3dbea0e06e9421652fcd77 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 18 Feb 2026 03:38:13 +0000 Subject: [PATCH] test: remove duplicated scenario scaffolding across runtime tests --- .../isolated-agent/run.skill-filter.test.ts | 35 ++---- .../bundled/session-memory/handler.test.ts | 64 +++++------ src/imessage/monitor.gating.test.ts | 43 +++----- src/plugins/voice-call.plugin.test.ts | 101 +++++++----------- 4 files changed, 90 insertions(+), 153 deletions(-) diff --git a/src/cron/isolated-agent/run.skill-filter.test.ts b/src/cron/isolated-agent/run.skill-filter.test.ts index 7fb8703f0e9..fad50f77d81 100644 --- a/src/cron/isolated-agent/run.skill-filter.test.ts +++ b/src/cron/isolated-agent/run.skill-filter.test.ts @@ -359,9 +359,8 @@ describe("runCronIsolatedAgentTurn — skill filter", () => { "nvidia/deepseek-ai/deepseek-v3.2", ]; - it("preserves defaults when agent overrides primary as string", async () => { - resolveAgentConfigMock.mockReturnValue({ model: "anthropic/claude-sonnet-4-5" }); - + async function expectPrimaryOverridePreservesDefaults(modelOverride: unknown) { + resolveAgentConfigMock.mockReturnValue({ model: modelOverride }); const result = await runCronIsolatedAgentTurn( makeParams({ cfg: { @@ -383,34 +382,14 @@ describe("runCronIsolatedAgentTurn — skill filter", () => { | undefined; expect(model?.primary).toBe("anthropic/claude-sonnet-4-5"); expect(model?.fallbacks).toEqual(defaultFallbacks); + } + + it("preserves defaults when agent overrides primary as string", async () => { + await expectPrimaryOverridePreservesDefaults("anthropic/claude-sonnet-4-5"); }); it("preserves defaults when agent overrides primary in object form", async () => { - resolveAgentConfigMock.mockReturnValue({ - model: { primary: "anthropic/claude-sonnet-4-5" }, - }); - - const result = await runCronIsolatedAgentTurn( - makeParams({ - cfg: { - agents: { - defaults: { - model: { primary: "openai-codex/gpt-5.3-codex", fallbacks: defaultFallbacks }, - }, - }, - }, - agentId: "scout", - }), - ); - - expect(result.status).toBe("ok"); - expect(runWithModelFallbackMock).toHaveBeenCalledOnce(); - const callCfg = runWithModelFallbackMock.mock.calls[0][0].cfg; - const model = callCfg?.agents?.defaults?.model as - | { primary?: string; fallbacks?: string[] } - | undefined; - expect(model?.primary).toBe("anthropic/claude-sonnet-4-5"); - expect(model?.fallbacks).toEqual(defaultFallbacks); + await expectPrimaryOverridePreservesDefaults({ primary: "anthropic/claude-sonnet-4-5" }); }); }); }); diff --git a/src/hooks/bundled/session-memory/handler.test.ts b/src/hooks/bundled/session-memory/handler.test.ts index af0e021544c..e934769378a 100644 --- a/src/hooks/bundled/session-memory/handler.test.ts +++ b/src/hooks/bundled/session-memory/handler.test.ts @@ -40,6 +40,29 @@ function createMockSessionContent( .join("\n"); } +async function runNewWithPreviousSessionEntry(params: { + tempDir: string; + previousSessionEntry: { sessionId: string; sessionFile?: string }; + cfg?: OpenClawConfig; +}): Promise<{ files: string[]; memoryContent: string }> { + const event = createHookEvent("command", "new", "agent:main:main", { + cfg: + params.cfg ?? + ({ + agents: { defaults: { workspace: params.tempDir } }, + } satisfies OpenClawConfig), + previousSessionEntry: params.previousSessionEntry, + }); + + await handler(event); + + const memoryDir = path.join(params.tempDir, "memory"); + const files = await fs.readdir(memoryDir); + const memoryContent = + files.length > 0 ? await fs.readFile(path.join(memoryDir, files[0]), "utf-8") : ""; + return { files, memoryContent }; +} + async function runNewWithPreviousSession(params: { sessionContent: string; cfg?: (tempDir: string) => OpenClawConfig; @@ -60,21 +83,14 @@ async function runNewWithPreviousSession(params: { agents: { defaults: { workspace: tempDir } }, } satisfies OpenClawConfig); - const event = createHookEvent("command", "new", "agent:main:main", { + const { files, memoryContent } = await runNewWithPreviousSessionEntry({ + tempDir, cfg, previousSessionEntry: { sessionId: "test-123", sessionFile, }, }); - - await handler(event); - - const memoryDir = path.join(tempDir, "memory"); - const files = await fs.readdir(memoryDir); - const memoryContent = - files.length > 0 ? await fs.readFile(path.join(memoryDir, files[0]), "utf-8") : ""; - return { tempDir, files, memoryContent }; } @@ -277,25 +293,14 @@ describe("session-memory hook", () => { content: resetContent, }); - const cfg = { - agents: { defaults: { workspace: tempDir } }, - } satisfies OpenClawConfig; - - const event = createHookEvent("command", "new", "agent:main:main", { - cfg, + const { memoryContent } = await runNewWithPreviousSessionEntry({ + tempDir, previousSessionEntry: { sessionId: "test-123", sessionFile: activeSessionFile, }, }); - await handler(event); - - const memoryDir = path.join(tempDir, "memory"); - const files = await fs.readdir(memoryDir); - expect(files.length).toBe(1); - const memoryContent = await fs.readFile(path.join(memoryDir, files[0]), "utf-8"); - expect(memoryContent).toContain("user: Message from rotated transcript"); expect(memoryContent).toContain("assistant: Recovered from reset fallback"); }); @@ -408,25 +413,14 @@ describe("session-memory hook", () => { ]), }); - const cfg = { - agents: { defaults: { workspace: tempDir } }, - } satisfies OpenClawConfig; - - const event = createHookEvent("command", "new", "agent:main:main", { - cfg, + const { memoryContent } = await runNewWithPreviousSessionEntry({ + tempDir, previousSessionEntry: { sessionId: "test-123", sessionFile: activeSessionFile, }, }); - await handler(event); - - const memoryDir = path.join(tempDir, "memory"); - const files = await fs.readdir(memoryDir); - expect(files.length).toBe(1); - const memoryContent = await fs.readFile(path.join(memoryDir, files[0]), "utf-8"); - expect(memoryContent).toContain("user: Newest rotated transcript"); expect(memoryContent).toContain("assistant: Newest summary"); expect(memoryContent).not.toContain("Older rotated transcript"); diff --git a/src/imessage/monitor.gating.test.ts b/src/imessage/monitor.gating.test.ts index 8180a40c890..36a324e009b 100644 --- a/src/imessage/monitor.gating.test.ts +++ b/src/imessage/monitor.gating.test.ts @@ -48,16 +48,19 @@ function resolve(params: { }); } -function buildDispatchContextPayload(params: { cfg: OpenClawConfig; message: IMessagePayload }) { - const { cfg, message } = params; - const groupHistories = new Map(); +function resolveDispatchDecision(params: { + cfg: OpenClawConfig; + message: IMessagePayload; + groupHistories?: Parameters[0]["groupHistories"]; +}) { + const groupHistories = params.groupHistories ?? new Map(); const decision = resolveIMessageInboundDecision({ - cfg, + cfg: params.cfg, accountId: "default", - message, + message: params.message, opts: {}, - messageText: message.text ?? "", - bodyText: message.text ?? "", + messageText: params.message.text ?? "", + bodyText: params.message.text ?? "", allowFrom: ["*"], groupAllowFrom: [], groupPolicy: "open", @@ -70,6 +73,12 @@ function buildDispatchContextPayload(params: { cfg: OpenClawConfig; message: IMe if (decision.kind !== "dispatch") { throw new Error("expected dispatch decision"); } + return { decision, groupHistories }; +} + +function buildDispatchContextPayload(params: { cfg: OpenClawConfig; message: IMessagePayload }) { + const { cfg, message } = params; + const { decision, groupHistories } = resolveDispatchDecision({ cfg, message }); const { ctxPayload } = buildIMessageInboundContext({ cfg, @@ -167,25 +176,7 @@ describe("imessage monitor gating + envelope builders", () => { text: "hello", is_group: false, }; - const decision = resolveIMessageInboundDecision({ - cfg, - accountId: "default", - message, - opts: {}, - messageText: message.text ?? "", - bodyText: message.text ?? "", - allowFrom: ["*"], - groupAllowFrom: [], - groupPolicy: "open", - dmPolicy: "open", - storeAllowFrom: [], - historyLimit: 0, - groupHistories, - }); - expect(decision.kind).toBe("dispatch"); - if (decision.kind !== "dispatch") { - throw new Error("expected dispatch decision"); - } + const { decision } = resolveDispatchDecision({ cfg, message, groupHistories }); expect(decision.isGroup).toBe(true); expect(decision.route.sessionKey).toBe("agent:main:imessage:group:2"); }); diff --git a/src/plugins/voice-call.plugin.test.ts b/src/plugins/voice-call.plugin.test.ts index f978defe198..0ca6106d1a9 100644 --- a/src/plugins/voice-call.plugin.test.ts +++ b/src/plugins/voice-call.plugin.test.ts @@ -34,6 +34,13 @@ type Registered = { methods: Map; tools: unknown[]; }; +type RegisterVoiceCall = (api: Record) => void | Promise; +type RegisterCliContext = { + program: Command; + config: Record; + workspaceDir?: string; + logger: typeof noopLogger; +}; function setup(config: Record): Registered { const methods = new Map(); @@ -59,6 +66,34 @@ function setup(config: Record): Registered { return { methods, tools }; } +async function registerVoiceCallCli(program: Command) { + const { register } = plugin as unknown as { + register: RegisterVoiceCall; + }; + await register({ + id: "voice-call", + name: "Voice Call", + description: "test", + version: "0", + source: "test", + config: {}, + pluginConfig: { provider: "mock" }, + runtime: { tts: { textToSpeechTelephony: vi.fn() } }, + logger: noopLogger, + registerGatewayMethod: () => {}, + registerTool: () => {}, + registerCli: (fn: (ctx: RegisterCliContext) => void) => + fn({ + program, + config: {}, + workspaceDir: undefined, + logger: noopLogger, + }), + registerService: () => {}, + resolvePath: (p: string) => p, + }); +} + describe("voice-call plugin", () => { beforeEach(() => { runtimeStub = { @@ -145,9 +180,6 @@ describe("voice-call plugin", () => { }); it("CLI latency summarizes turn metrics from JSONL", async () => { - const { register } = plugin as unknown as { - register: (api: Record) => void | Promise; - }; const program = new Command(); const tmpFile = path.join(os.tmpdir(), `voicecall-latency-${Date.now()}.jsonl`); fs.writeFileSync( @@ -162,35 +194,7 @@ describe("voice-call plugin", () => { const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); try { - await register({ - id: "voice-call", - name: "Voice Call", - description: "test", - version: "0", - source: "test", - config: {}, - pluginConfig: { provider: "mock" }, - runtime: { tts: { textToSpeechTelephony: vi.fn() } }, - logger: noopLogger, - registerGatewayMethod: () => {}, - registerTool: () => {}, - registerCli: ( - fn: (ctx: { - program: Command; - config: Record; - workspaceDir?: string; - logger: typeof noopLogger; - }) => void, - ) => - fn({ - program, - config: {}, - workspaceDir: undefined, - logger: noopLogger, - }), - registerService: () => {}, - resolvePath: (p: string) => p, - }); + await registerVoiceCallCli(program); await program.parseAsync(["voicecall", "latency", "--file", tmpFile, "--last", "10"], { from: "user", @@ -208,40 +212,9 @@ describe("voice-call plugin", () => { }); it("CLI start prints JSON", async () => { - const { register } = plugin as unknown as { - register: (api: Record) => void | Promise; - }; const program = new Command(); const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); - await register({ - id: "voice-call", - name: "Voice Call", - description: "test", - version: "0", - source: "test", - config: {}, - pluginConfig: { provider: "mock" }, - runtime: { tts: { textToSpeechTelephony: vi.fn() } }, - logger: noopLogger, - registerGatewayMethod: () => {}, - registerTool: () => {}, - registerCli: ( - fn: (ctx: { - program: Command; - config: Record; - workspaceDir?: string; - logger: typeof noopLogger; - }) => void, - ) => - fn({ - program, - config: {}, - workspaceDir: undefined, - logger: noopLogger, - }), - registerService: () => {}, - resolvePath: (p: string) => p, - }); + await registerVoiceCallCli(program); await program.parseAsync(["voicecall", "start", "--to", "+1", "--message", "Hello"], { from: "user",