From a76a9c375f8e40328312ad133cd5a6afc26bd6d0 Mon Sep 17 00:00:00 2001 From: cpojer Date: Tue, 17 Feb 2026 11:59:17 +0900 Subject: [PATCH] chore: Fix types in tests 15/N. --- ....invoke.nodes-run-approval-timeout.test.ts | 2 +- src/cli/program/message/helpers.test.ts | 4 +- ...s-last-non-empty-agent-text-as.e2e.test.ts | 2 +- src/cron/service.issue-regressions.test.ts | 42 ++++++++---- src/line/bot-handlers.test.ts | 8 +-- ...t-handler.typing-read-receipts.e2e.test.ts | 11 ++-- src/slack/monitor/media.test.ts | 65 ++++++++++--------- 7 files changed, 75 insertions(+), 59 deletions(-) diff --git a/src/cli/nodes-cli/register.invoke.nodes-run-approval-timeout.test.ts b/src/cli/nodes-cli/register.invoke.nodes-run-approval-timeout.test.ts index 7d7ff6b9e..dfb4bd4dc 100644 --- a/src/cli/nodes-cli/register.invoke.nodes-run-approval-timeout.test.ts +++ b/src/cli/nodes-cli/register.invoke.nodes-run-approval-timeout.test.ts @@ -22,7 +22,7 @@ import { parseTimeoutMs } from "../nodes-run.js"; const callGatewaySpy = vi.fn(async () => ({ decision: "allow-once" })); vi.mock("../../gateway/call.js", () => ({ - callGateway: (...args: unknown[]) => callGatewaySpy(...args), + callGateway: callGatewaySpy, randomIdempotencyKey: () => "mock-key", })); diff --git a/src/cli/program/message/helpers.test.ts b/src/cli/program/message/helpers.test.ts index 7188c26b4..bee38e1e3 100644 --- a/src/cli/program/message/helpers.test.ts +++ b/src/cli/program/message/helpers.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const messageCommandMock = vi.fn(async () => {}); vi.mock("../../../commands/message.js", () => ({ - messageCommand: (...args: unknown[]) => messageCommandMock(...args), + messageCommand: messageCommandMock, })); vi.mock("../../../globals.js", () => ({ @@ -33,7 +33,7 @@ const runGlobalGatewayStopSafelyMock = vi.fn( }, ); vi.mock("../../../plugins/hook-runner-global.js", () => ({ - runGlobalGatewayStopSafely: (...args: unknown[]) => runGlobalGatewayStopSafelyMock(...args), + runGlobalGatewayStopSafely: runGlobalGatewayStopSafelyMock, })); const exitMock = vi.fn((): never => { diff --git a/src/cron/isolated-agent.uses-last-non-empty-agent-text-as.e2e.test.ts b/src/cron/isolated-agent.uses-last-non-empty-agent-text-as.e2e.test.ts index 920f46572..cdbd3c7ee 100644 --- a/src/cron/isolated-agent.uses-last-non-empty-agent-text-as.e2e.test.ts +++ b/src/cron/isolated-agent.uses-last-non-empty-agent-text-as.e2e.test.ts @@ -383,7 +383,7 @@ describe("runCronIsolatedAgentTurn", () => { cfgOverrides: { agents: { defaults: { - model: "anthropic/claude-opus-4-5", + model: { primary: "anthropic/claude-opus-4-5" }, models: { "anthropic/claude-opus-4-5": { alias: "Opus" }, }, diff --git a/src/cron/service.issue-regressions.test.ts b/src/cron/service.issue-regressions.test.ts index dc892d8a2..87e98d69b 100644 --- a/src/cron/service.issue-regressions.test.ts +++ b/src/cron/service.issue-regressions.test.ts @@ -5,7 +5,7 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } import { CronService } from "./service.js"; import { createCronServiceState, type CronEvent } from "./service/state.js"; import { onTimer } from "./service/timer.js"; -import type { CronJob } from "./types.js"; +import type { CronJob, CronJobState } from "./types.js"; const noopLogger = { info: vi.fn(), @@ -93,8 +93,10 @@ describe("Cron issue regressions", () => { const created = await cron.add({ name: "hourly", + enabled: true, schedule: { kind: "cron", expr: "0 * * * *", tz: "UTC" }, sessionTarget: "main", + wakeMode: "next-heartbeat", payload: { kind: "systemEvent", text: "tick" }, }); expect(created.state.nextRunAtMs).toBe(Date.parse("2026-02-06T11:00:00.000Z")); @@ -107,8 +109,10 @@ describe("Cron issue regressions", () => { const forceNow = await cron.add({ name: "force-now", + enabled: true, schedule: { kind: "every", everyMs: 60_000, anchorMs: Date.now() }, sessionTarget: "main", + wakeMode: "next-heartbeat", payload: { kind: "systemEvent", text: "force" }, }); @@ -122,8 +126,10 @@ describe("Cron issue regressions", () => { const job = await cron.add({ name: "isolated", + enabled: true, schedule: { kind: "every", everyMs: 60_000, anchorMs: Date.now() }, sessionTarget: "isolated", + wakeMode: "next-heartbeat", payload: { kind: "agentTurn", message: "hi" }, }); const status = await cron.status(); @@ -133,8 +139,10 @@ describe("Cron issue regressions", () => { const unsafeToggle = await cron.add({ name: "unsafe toggle", + enabled: true, schedule: { kind: "every", everyMs: 60_000, anchorMs: Date.now() }, sessionTarget: "isolated", + wakeMode: "next-heartbeat", payload: { kind: "agentTurn", message: "hi" }, }); @@ -165,8 +173,10 @@ describe("Cron issue regressions", () => { const created = await cron.add({ name: "repair-target", + enabled: true, schedule: { kind: "cron", expr: "0 * * * *", tz: "UTC" }, sessionTarget: "main", + wakeMode: "next-heartbeat", payload: { kind: "systemEvent", text: "tick" }, }); const updated = await cron.update(created.id, { @@ -197,14 +207,18 @@ describe("Cron issue regressions", () => { const dueJob = await cron.add({ name: "due-preserved", + enabled: true, schedule: { kind: "every", everyMs: 60_000, anchorMs: now }, sessionTarget: "main", + wakeMode: "next-heartbeat", payload: { kind: "systemEvent", text: "due-preserved" }, }); const otherJob = await cron.add({ name: "other-job", + enabled: true, schedule: { kind: "cron", expr: "0 * * * *", tz: "UTC" }, sessionTarget: "main", + wakeMode: "next-heartbeat", payload: { kind: "systemEvent", text: "other" }, }); @@ -344,6 +358,7 @@ describe("Cron issue regressions", () => { const callsBeforeAdd = timeoutSpy.mock.calls.length; await cron.add({ name: "far-future", + enabled: true, schedule: { kind: "at", at: "2035-01-01T00:00:00.000Z" }, sessionTarget: "main", wakeMode: "next-heartbeat", @@ -473,25 +488,26 @@ describe("Cron issue regressions", () => { wakeMode: "now", payload: { kind: "systemEvent", text: "⏰ Reminder" }, } as const; - for (const [id, state] of [ - [ - "oneshot-skipped", - { + const terminalStates: Array<{ id: string; state: CronJobState }> = [ + { + id: "oneshot-skipped", + state: { nextRunAtMs: pastAt, - lastStatus: "skipped" as const, + lastStatus: "skipped", lastRunAtMs: pastAt, }, - ], - [ - "oneshot-errored", - { + }, + { + id: "oneshot-errored", + state: { nextRunAtMs: pastAt, - lastStatus: "error" as const, + lastStatus: "error", lastRunAtMs: pastAt, lastError: "heartbeat failed", }, - ], - ]) { + }, + ]; + for (const { id, state } of terminalStates) { const job: CronJob = { id, ...baseJob, state }; await fs.writeFile( store.storePath, diff --git a/src/line/bot-handlers.test.ts b/src/line/bot-handlers.test.ts index bf4c108a5..369c181b5 100644 --- a/src/line/bot-handlers.test.ts +++ b/src/line/bot-handlers.test.ts @@ -43,8 +43,8 @@ const { buildLineMessageContextMock, buildLinePostbackContextMock } = vi.hoisted })); vi.mock("./bot-message-context.js", () => ({ - buildLineMessageContext: (...args: unknown[]) => buildLineMessageContextMock(...args), - buildLinePostbackContext: (...args: unknown[]) => buildLinePostbackContextMock(...args), + buildLineMessageContext: buildLineMessageContextMock, + buildLinePostbackContext: buildLinePostbackContextMock, getLineSourceInfo: (source: { type?: string; userId?: string; @@ -66,8 +66,8 @@ const { readAllowFromStoreMock, upsertPairingRequestMock } = vi.hoisted(() => ({ let handleLineWebhookEvents: typeof import("./bot-handlers.js").handleLineWebhookEvents; vi.mock("../pairing/pairing-store.js", () => ({ - readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args), - upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args), + readChannelAllowFromStore: readAllowFromStoreMock, + upsertChannelPairingRequest: upsertPairingRequestMock, })); describe("handleLineWebhookEvents", () => { diff --git a/src/signal/monitor.event-handler.typing-read-receipts.e2e.test.ts b/src/signal/monitor.event-handler.typing-read-receipts.e2e.test.ts index 9555764f0..336d599bc 100644 --- a/src/signal/monitor.event-handler.typing-read-receipts.e2e.test.ts +++ b/src/signal/monitor.event-handler.typing-read-receipts.e2e.test.ts @@ -12,15 +12,14 @@ const dispatchInboundMessageMock = vi.fn( vi.mock("./send.js", () => ({ sendMessageSignal: vi.fn(), - sendTypingSignal: (...args: unknown[]) => sendTypingMock(...args), - sendReadReceiptSignal: (...args: unknown[]) => sendReadReceiptMock(...args), + sendTypingSignal: sendTypingMock, + sendReadReceiptSignal: sendReadReceiptMock, })); vi.mock("../auto-reply/dispatch.js", () => ({ - dispatchInboundMessage: (...args: unknown[]) => dispatchInboundMessageMock(...args), - dispatchInboundMessageWithDispatcher: (...args: unknown[]) => dispatchInboundMessageMock(...args), - dispatchInboundMessageWithBufferedDispatcher: (...args: unknown[]) => - dispatchInboundMessageMock(...args), + dispatchInboundMessage: dispatchInboundMessageMock, + dispatchInboundMessageWithDispatcher: dispatchInboundMessageMock, + dispatchInboundMessageWithBufferedDispatcher: dispatchInboundMessageMock, })); vi.mock("../pairing/pairing-store.js", () => ({ diff --git a/src/slack/monitor/media.test.ts b/src/slack/monitor/media.test.ts index f708f3819..547b4b4d1 100644 --- a/src/slack/monitor/media.test.ts +++ b/src/slack/monitor/media.test.ts @@ -1,6 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import * as ssrf from "../../infra/net/ssrf.js"; import * as mediaStore from "../../media/store.js"; +import type { SavedMedia } from "../../media/store.js"; import { fetchWithSlackAuth, resolveSlackAttachmentContent, @@ -11,6 +12,12 @@ import { // Store original fetch const originalFetch = globalThis.fetch; let mockFetch: ReturnType; +const createSavedMedia = (filePath: string, contentType: string): SavedMedia => ({ + id: "saved-media-id", + path: filePath, + size: 128, + contentType, +}); describe("fetchWithSlackAuth", () => { beforeEach(() => { @@ -180,10 +187,9 @@ describe("resolveSlackMedia", () => { }); it("prefers url_private_download over url_private", async () => { - vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/test.jpg", - contentType: "image/jpeg", - }); + vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue( + createSavedMedia("/tmp/test.jpg", "image/jpeg"), + ); const mockResponse = new Response(Buffer.from("image data"), { status: 200, @@ -247,10 +253,9 @@ describe("resolveSlackMedia", () => { // saveMediaBuffer re-detects MIME from buffer bytes, so it may return // video/mp4 for MP4 containers. Verify resolveSlackMedia preserves // the overridden audio/* type in its return value despite this. - const saveMediaBufferMock = vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/voice.mp4", - contentType: "video/mp4", - }); + const saveMediaBufferMock = vi + .spyOn(mediaStore, "saveMediaBuffer") + .mockResolvedValue(createSavedMedia("/tmp/voice.mp4", "video/mp4")); const mockResponse = new Response(Buffer.from("audio data"), { status: 200, @@ -286,10 +291,9 @@ describe("resolveSlackMedia", () => { }); it("preserves original MIME for non-voice Slack files", async () => { - const saveMediaBufferMock = vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/video.mp4", - contentType: "video/mp4", - }); + const saveMediaBufferMock = vi + .spyOn(mediaStore, "saveMediaBuffer") + .mockResolvedValue(createSavedMedia("/tmp/video.mp4", "video/mp4")); const mockResponse = new Response(Buffer.from("video data"), { status: 200, @@ -321,10 +325,9 @@ describe("resolveSlackMedia", () => { }); it("falls through to next file when first file returns error", async () => { - vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/test.jpg", - contentType: "image/jpeg", - }); + vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue( + createSavedMedia("/tmp/test.jpg", "image/jpeg"), + ); // First file: 404 const errorResponse = new Response("Not Found", { status: 404 }); @@ -351,15 +354,15 @@ describe("resolveSlackMedia", () => { }); it("returns all successfully downloaded files as an array", async () => { - vi.spyOn(mediaStore, "saveMediaBuffer").mockImplementation(async (buffer) => { + vi.spyOn(mediaStore, "saveMediaBuffer").mockImplementation(async (buffer, _contentType) => { const text = Buffer.from(buffer).toString("utf8"); if (text.includes("image a")) { - return { path: "/tmp/a.jpg", contentType: "image/jpeg" }; + return createSavedMedia("/tmp/a.jpg", "image/jpeg"); } if (text.includes("image b")) { - return { path: "/tmp/b.png", contentType: "image/png" }; + return createSavedMedia("/tmp/b.png", "image/png"); } - return { path: "/tmp/unknown", contentType: "application/octet-stream" }; + return createSavedMedia("/tmp/unknown", "application/octet-stream"); }); mockFetch.mockImplementation(async (input) => { @@ -396,10 +399,9 @@ describe("resolveSlackMedia", () => { }); it("caps downloads to 8 files for large multi-attachment messages", async () => { - const saveMediaBufferMock = vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/x.jpg", - contentType: "image/jpeg", - }); + const saveMediaBufferMock = vi + .spyOn(mediaStore, "saveMediaBuffer") + .mockResolvedValue(createSavedMedia("/tmp/x.jpg", "image/jpeg")); mockFetch.mockImplementation(async () => { return new Response(Buffer.from("image data"), { @@ -499,10 +501,9 @@ describe("resolveSlackAttachmentContent", () => { }); it("downloads Slack-hosted images from forwarded shared attachments", async () => { - vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({ - path: "/tmp/forwarded.jpg", - contentType: "image/jpeg", - }); + vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue( + createSavedMedia("/tmp/forwarded.jpg", "image/jpeg"), + ); mockFetch.mockResolvedValueOnce( new Response(Buffer.from("forwarded image"), { @@ -556,7 +557,7 @@ describe("resolveSlackThreadHistory", () => { }); const client = { conversations: { replies }, - } as Parameters[0]["client"]; + } as unknown as Parameters[0]["client"]; const result = await resolveSlackThreadHistory({ channelId: "C1", @@ -606,7 +607,7 @@ describe("resolveSlackThreadHistory", () => { }); const client = { conversations: { replies }, - } as Parameters[0]["client"]; + } as unknown as Parameters[0]["client"]; const result = await resolveSlackThreadHistory({ channelId: "C1", @@ -624,7 +625,7 @@ describe("resolveSlackThreadHistory", () => { const replies = vi.fn(); const client = { conversations: { replies }, - } as Parameters[0]["client"]; + } as unknown as Parameters[0]["client"]; const result = await resolveSlackThreadHistory({ channelId: "C1", @@ -641,7 +642,7 @@ describe("resolveSlackThreadHistory", () => { const replies = vi.fn().mockRejectedValueOnce(new Error("slack down")); const client = { conversations: { replies }, - } as Parameters[0]["client"]; + } as unknown as Parameters[0]["client"]; const result = await resolveSlackThreadHistory({ channelId: "C1",