Spaces:
Sleeping
Sleeping
| import type { MessageEvent } from "@line/bot-sdk"; | |
| import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; | |
| const { buildLineMessageContextMock, buildLinePostbackContextMock } = vi.hoisted(() => ({ | |
| buildLineMessageContextMock: vi.fn(async () => ({ | |
| ctxPayload: { From: "line:group:group-1" }, | |
| replyToken: "reply-token", | |
| route: { agentId: "default" }, | |
| isGroup: true, | |
| accountId: "default", | |
| })), | |
| buildLinePostbackContextMock: vi.fn(async () => null), | |
| })); | |
| vi.mock("./bot-message-context.js", () => ({ | |
| buildLineMessageContext: (...args: unknown[]) => buildLineMessageContextMock(...args), | |
| buildLinePostbackContext: (...args: unknown[]) => buildLinePostbackContextMock(...args), | |
| })); | |
| const { readAllowFromStoreMock, upsertPairingRequestMock } = vi.hoisted(() => ({ | |
| readAllowFromStoreMock: vi.fn(async () => [] as string[]), | |
| upsertPairingRequestMock: vi.fn(async () => ({ code: "CODE", created: true })), | |
| })); | |
| let handleLineWebhookEvents: typeof import("./bot-handlers.js").handleLineWebhookEvents; | |
| vi.mock("../pairing/pairing-store.js", () => ({ | |
| readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args), | |
| upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args), | |
| })); | |
| describe("handleLineWebhookEvents", () => { | |
| beforeAll(async () => { | |
| ({ handleLineWebhookEvents } = await import("./bot-handlers.js")); | |
| }); | |
| beforeEach(() => { | |
| buildLineMessageContextMock.mockClear(); | |
| buildLinePostbackContextMock.mockClear(); | |
| readAllowFromStoreMock.mockClear(); | |
| upsertPairingRequestMock.mockClear(); | |
| }); | |
| it("blocks group messages when groupPolicy is disabled", async () => { | |
| const processMessage = vi.fn(); | |
| const event = { | |
| type: "message", | |
| message: { id: "m1", type: "text", text: "hi" }, | |
| replyToken: "reply-token", | |
| timestamp: Date.now(), | |
| source: { type: "group", groupId: "group-1", userId: "user-1" }, | |
| mode: "active", | |
| webhookEventId: "evt-1", | |
| deliveryContext: { isRedelivery: false }, | |
| } as MessageEvent; | |
| await handleLineWebhookEvents([event], { | |
| cfg: { channels: { line: { groupPolicy: "disabled" } } }, | |
| account: { | |
| accountId: "default", | |
| enabled: true, | |
| channelAccessToken: "token", | |
| channelSecret: "secret", | |
| tokenSource: "config", | |
| config: { groupPolicy: "disabled" }, | |
| }, | |
| runtime: { error: vi.fn() }, | |
| mediaMaxBytes: 1, | |
| processMessage, | |
| }); | |
| expect(processMessage).not.toHaveBeenCalled(); | |
| expect(buildLineMessageContextMock).not.toHaveBeenCalled(); | |
| }); | |
| it("blocks group messages when allowlist is empty", async () => { | |
| const processMessage = vi.fn(); | |
| const event = { | |
| type: "message", | |
| message: { id: "m2", type: "text", text: "hi" }, | |
| replyToken: "reply-token", | |
| timestamp: Date.now(), | |
| source: { type: "group", groupId: "group-1", userId: "user-2" }, | |
| mode: "active", | |
| webhookEventId: "evt-2", | |
| deliveryContext: { isRedelivery: false }, | |
| } as MessageEvent; | |
| await handleLineWebhookEvents([event], { | |
| cfg: { channels: { line: { groupPolicy: "allowlist" } } }, | |
| account: { | |
| accountId: "default", | |
| enabled: true, | |
| channelAccessToken: "token", | |
| channelSecret: "secret", | |
| tokenSource: "config", | |
| config: { groupPolicy: "allowlist" }, | |
| }, | |
| runtime: { error: vi.fn() }, | |
| mediaMaxBytes: 1, | |
| processMessage, | |
| }); | |
| expect(processMessage).not.toHaveBeenCalled(); | |
| expect(buildLineMessageContextMock).not.toHaveBeenCalled(); | |
| }); | |
| it("allows group messages when sender is in groupAllowFrom", async () => { | |
| const processMessage = vi.fn(); | |
| const event = { | |
| type: "message", | |
| message: { id: "m3", type: "text", text: "hi" }, | |
| replyToken: "reply-token", | |
| timestamp: Date.now(), | |
| source: { type: "group", groupId: "group-1", userId: "user-3" }, | |
| mode: "active", | |
| webhookEventId: "evt-3", | |
| deliveryContext: { isRedelivery: false }, | |
| } as MessageEvent; | |
| await handleLineWebhookEvents([event], { | |
| cfg: { | |
| channels: { line: { groupPolicy: "allowlist", groupAllowFrom: ["user-3"] } }, | |
| }, | |
| account: { | |
| accountId: "default", | |
| enabled: true, | |
| channelAccessToken: "token", | |
| channelSecret: "secret", | |
| tokenSource: "config", | |
| config: { groupPolicy: "allowlist", groupAllowFrom: ["user-3"] }, | |
| }, | |
| runtime: { error: vi.fn() }, | |
| mediaMaxBytes: 1, | |
| processMessage, | |
| }); | |
| expect(buildLineMessageContextMock).toHaveBeenCalledTimes(1); | |
| expect(processMessage).toHaveBeenCalledTimes(1); | |
| }); | |
| it("blocks group messages when wildcard group config disables groups", async () => { | |
| const processMessage = vi.fn(); | |
| const event = { | |
| type: "message", | |
| message: { id: "m4", type: "text", text: "hi" }, | |
| replyToken: "reply-token", | |
| timestamp: Date.now(), | |
| source: { type: "group", groupId: "group-2", userId: "user-4" }, | |
| mode: "active", | |
| webhookEventId: "evt-4", | |
| deliveryContext: { isRedelivery: false }, | |
| } as MessageEvent; | |
| await handleLineWebhookEvents([event], { | |
| cfg: { channels: { line: { groupPolicy: "open" } } }, | |
| account: { | |
| accountId: "default", | |
| enabled: true, | |
| channelAccessToken: "token", | |
| channelSecret: "secret", | |
| tokenSource: "config", | |
| config: { groupPolicy: "open", groups: { "*": { enabled: false } } }, | |
| }, | |
| runtime: { error: vi.fn() }, | |
| mediaMaxBytes: 1, | |
| processMessage, | |
| }); | |
| expect(processMessage).not.toHaveBeenCalled(); | |
| expect(buildLineMessageContextMock).not.toHaveBeenCalled(); | |
| }); | |
| }); | |