mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-30 01:06:11 +00:00
chore: Fix types in tests 15/N.
This commit is contained in:
@@ -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",
|
||||
}));
|
||||
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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" },
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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", () => ({
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user