chore: Fix types in tests 15/N.

This commit is contained in:
cpojer
2026-02-17 11:59:17 +09:00
parent db3529e924
commit a76a9c375f
7 changed files with 75 additions and 59 deletions

View File

@@ -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",
}));

View File

@@ -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 => {

View File

@@ -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" },
},

View File

@@ -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,

View File

@@ -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", () => {

View File

@@ -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", () => ({

View File

@@ -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<typeof vi.fn>;
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<typeof resolveSlackThreadHistory>[0]["client"];
} as unknown as Parameters<typeof resolveSlackThreadHistory>[0]["client"];
const result = await resolveSlackThreadHistory({
channelId: "C1",
@@ -606,7 +607,7 @@ describe("resolveSlackThreadHistory", () => {
});
const client = {
conversations: { replies },
} as Parameters<typeof resolveSlackThreadHistory>[0]["client"];
} as unknown as Parameters<typeof resolveSlackThreadHistory>[0]["client"];
const result = await resolveSlackThreadHistory({
channelId: "C1",
@@ -624,7 +625,7 @@ describe("resolveSlackThreadHistory", () => {
const replies = vi.fn();
const client = {
conversations: { replies },
} as Parameters<typeof resolveSlackThreadHistory>[0]["client"];
} as unknown as Parameters<typeof resolveSlackThreadHistory>[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<typeof resolveSlackThreadHistory>[0]["client"];
} as unknown as Parameters<typeof resolveSlackThreadHistory>[0]["client"];
const result = await resolveSlackThreadHistory({
channelId: "C1",