diff --git a/extensions/line/src/webhook-node.test.ts b/extensions/line/src/webhook-node.test.ts index c260155e1045..bfacb98807f4 100644 --- a/extensions/line/src/webhook-node.test.ts +++ b/extensions/line/src/webhook-node.test.ts @@ -1,10 +1,10 @@ -// Line tests cover webhook node plugin behavior. import crypto from "node:crypto"; import type { IncomingMessage, ServerResponse } from "node:http"; import type { NextFunction, Request, Response } from "express"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { createMockIncomingRequest } from "openclaw/plugin-sdk/test-env"; import { afterAll, describe, expect, it, vi } from "vitest"; +import { createRuntimeSpies } from "../../test-support/runtime-spies.js"; const runDetachedWebhookWorkSpy = vi.hoisted(() => vi.fn()); vi.mock("openclaw/plugin-sdk/webhook-request-guards", async () => { @@ -71,20 +71,6 @@ function firstParsedPayload( return firstMockCall(mock, label)[0] as ParsedLineWebhookPayload; } -type RuntimeEnvMock = RuntimeEnv & { - error: ReturnType void>>; - exit: ReturnType void>>; - log: ReturnType void>>; -}; - -function createRuntimeMock(): RuntimeEnvMock { - return { - error: vi.fn<(...args: unknown[]) => void>(), - exit: vi.fn<(code: number) => void>(), - log: vi.fn<(...args: unknown[]) => void>(), - }; -} - function createMiddlewareRes() { const status = vi.fn(); const json = vi.fn(); @@ -106,7 +92,7 @@ function createMiddlewareRequest( function createPostWebhookTestHarness(rawBody: string, secret = "secret") { const bot = { handleWebhook: vi.fn(async () => "durable" as const) }; - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const handler = createLineNodeWebhookHandler({ channelSecret: secret, bot, @@ -200,7 +186,7 @@ async function invokeNodePostContract(params: { } return "durable" as const; }); - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const handler = createLineNodeWebhookHandler({ channelSecret: SECRET, bot: { handleWebhook: dispatched }, @@ -229,7 +215,7 @@ async function invokeMiddlewarePostContract(params: { rawBody: string; signed: boolean; }) { - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const onEvents = vi.fn(async () => { if (params.failWith) { // oxlint-disable-next-line typescript/only-throw-error -- Webhook boundaries must report non-Error throws from downstream dispatchers. @@ -371,7 +357,7 @@ describe("LINE webhook shared POST contract", () => { describe("createLineNodeWebhookHandler", () => { it("returns 200 for GET", async () => { const bot = { handleWebhook: vi.fn(async () => "durable" as const) }; - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const handler = createLineNodeWebhookHandler({ channelSecret: "secret", bot, @@ -388,7 +374,7 @@ describe("createLineNodeWebhookHandler", () => { it("returns 204 for HEAD", async () => { const bot = { handleWebhook: vi.fn(async () => "durable" as const) }; - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const handler = createLineNodeWebhookHandler({ channelSecret: "secret", bot, @@ -416,7 +402,7 @@ describe("createLineNodeWebhookHandler", () => { it("rejects unsigned POST requests before reading the body", async () => { const bot = { handleWebhook: vi.fn(async () => "durable" as const) }; - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const readBody = vi.fn(async () => JSON.stringify({ events: [{ type: "message" }] })); const handler = createLineNodeWebhookHandler({ channelSecret: "secret", @@ -436,7 +422,7 @@ describe("createLineNodeWebhookHandler", () => { it("uses strict pre-auth limits for signed POST requests", async () => { const rawBody = JSON.stringify({ events: [{ type: "message" }] }); const bot = { handleWebhook: vi.fn(async () => "durable" as const) }; - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const readBody = vi.fn(async (_req: IncomingMessage, maxBytes: number, timeoutMs?: number) => { expect(maxBytes).toBe(64 * 1024); expect(timeoutMs).toBe(5_000); @@ -498,7 +484,7 @@ describe("createLineNodeWebhookHandler", () => { ), }; const onRequestAuthenticated = vi.fn(); - const runtime = createRuntimeMock(); + const runtime = createRuntimeSpies(); const handler = createLineNodeWebhookHandler({ channelSecret: SECRET, bot,