diff --git a/src/agents/pi-embedded-runner.test.ts b/src/agents/pi-embedded-runner.e2e.test.ts similarity index 100% rename from src/agents/pi-embedded-runner.test.ts rename to src/agents/pi-embedded-runner.e2e.test.ts diff --git a/src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.ts b/src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts similarity index 100% rename from src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.ts rename to src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts diff --git a/src/agents/pi-model-discovery.compat.test.ts b/src/agents/pi-model-discovery.compat.e2e.test.ts similarity index 100% rename from src/agents/pi-model-discovery.compat.test.ts rename to src/agents/pi-model-discovery.compat.e2e.test.ts diff --git a/src/agents/pi-tools.before-tool-call.test.ts b/src/agents/pi-tools.before-tool-call.e2e.test.ts similarity index 100% rename from src/agents/pi-tools.before-tool-call.test.ts rename to src/agents/pi-tools.before-tool-call.e2e.test.ts diff --git a/src/agents/pi-tools.before-tool-call.integration.test.ts b/src/agents/pi-tools.before-tool-call.integration.e2e.test.ts similarity index 100% rename from src/agents/pi-tools.before-tool-call.integration.test.ts rename to src/agents/pi-tools.before-tool-call.integration.e2e.test.ts diff --git a/src/agents/sandbox-agent-config.agent-specific-sandbox-config.test.ts b/src/agents/sandbox-agent-config.agent-specific-sandbox-config.e2e.test.ts similarity index 100% rename from src/agents/sandbox-agent-config.agent-specific-sandbox-config.test.ts rename to src/agents/sandbox-agent-config.agent-specific-sandbox-config.e2e.test.ts diff --git a/src/agents/subagent-announce.format.test.ts b/src/agents/subagent-announce.format.e2e.test.ts similarity index 100% rename from src/agents/subagent-announce.format.test.ts rename to src/agents/subagent-announce.format.e2e.test.ts diff --git a/src/agents/subagent-registry.archive.test.ts b/src/agents/subagent-registry.archive.e2e.test.ts similarity index 100% rename from src/agents/subagent-registry.archive.test.ts rename to src/agents/subagent-registry.archive.e2e.test.ts diff --git a/src/agents/subagent-registry.lifecycle-retry-grace.test.ts b/src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts similarity index 100% rename from src/agents/subagent-registry.lifecycle-retry-grace.test.ts rename to src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts diff --git a/src/agents/subagent-registry.nested.test.ts b/src/agents/subagent-registry.nested.e2e.test.ts similarity index 100% rename from src/agents/subagent-registry.nested.test.ts rename to src/agents/subagent-registry.nested.e2e.test.ts diff --git a/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.test.ts b/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts similarity index 100% rename from src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.test.ts rename to src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts diff --git a/src/auto-reply/reply/agent-runner.runreplyagent.test.ts b/src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts similarity index 100% rename from src/auto-reply/reply/agent-runner.runreplyagent.test.ts rename to src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts diff --git a/src/browser/pw-ai.test.ts b/src/browser/pw-ai.e2e.test.ts similarity index 100% rename from src/browser/pw-ai.test.ts rename to src/browser/pw-ai.e2e.test.ts diff --git a/src/cli/program.nodes-basic.test.ts b/src/cli/program.nodes-basic.e2e.test.ts similarity index 100% rename from src/cli/program.nodes-basic.test.ts rename to src/cli/program.nodes-basic.e2e.test.ts diff --git a/src/cli/program.nodes-media.test.ts b/src/cli/program.nodes-media.e2e.test.ts similarity index 100% rename from src/cli/program.nodes-media.test.ts rename to src/cli/program.nodes-media.e2e.test.ts diff --git a/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts b/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts similarity index 100% rename from src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts rename to src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts diff --git a/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts b/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.e2e.test.ts similarity index 100% rename from src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts rename to src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.e2e.test.ts diff --git a/src/commands/doctor.warns-state-directory-is-missing.test.ts b/src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts similarity index 100% rename from src/commands/doctor.warns-state-directory-is-missing.test.ts rename to src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts diff --git a/src/commands/models.list.test.ts b/src/commands/models.list.e2e.test.ts similarity index 100% rename from src/commands/models.list.test.ts rename to src/commands/models.list.e2e.test.ts diff --git a/src/commands/models.set.test.ts b/src/commands/models.set.e2e.test.ts similarity index 100% rename from src/commands/models.set.test.ts rename to src/commands/models.set.e2e.test.ts diff --git a/src/commands/onboard-channels.test.ts b/src/commands/onboard-channels.e2e.test.ts similarity index 100% rename from src/commands/onboard-channels.test.ts rename to src/commands/onboard-channels.e2e.test.ts diff --git a/src/daemon/launchd.integration.test.ts b/src/daemon/launchd.integration.e2e.test.ts similarity index 100% rename from src/daemon/launchd.integration.test.ts rename to src/daemon/launchd.integration.e2e.test.ts diff --git a/src/discord/monitor.tool-result.accepts-guild-messages-mentionpatterns-match.test.ts b/src/discord/monitor.tool-result.accepts-guild-messages-mentionpatterns-match.e2e.test.ts similarity index 100% rename from src/discord/monitor.tool-result.accepts-guild-messages-mentionpatterns-match.test.ts rename to src/discord/monitor.tool-result.accepts-guild-messages-mentionpatterns-match.e2e.test.ts diff --git a/src/discord/voice/manager.test.ts b/src/discord/voice/manager.e2e.test.ts similarity index 100% rename from src/discord/voice/manager.test.ts rename to src/discord/voice/manager.e2e.test.ts diff --git a/src/docker-setup.test.ts b/src/docker-setup.e2e.test.ts similarity index 100% rename from src/docker-setup.test.ts rename to src/docker-setup.e2e.test.ts diff --git a/src/plugins/wired-hooks-after-tool-call.test.ts b/src/plugins/wired-hooks-after-tool-call.e2e.test.ts similarity index 100% rename from src/plugins/wired-hooks-after-tool-call.test.ts rename to src/plugins/wired-hooks-after-tool-call.e2e.test.ts diff --git a/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts b/src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts similarity index 100% rename from src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts rename to src/telegram/bot.media.downloads-media-file-path-no-file-download.e2e.test.ts diff --git a/src/telegram/bot.media.stickers-and-fragments.test.ts b/src/telegram/bot.media.stickers-and-fragments.e2e.test.ts similarity index 100% rename from src/telegram/bot.media.stickers-and-fragments.test.ts rename to src/telegram/bot.media.stickers-and-fragments.e2e.test.ts diff --git a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts b/src/web/auto-reply.broadcast-groups.combined.test.ts similarity index 89% rename from src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts rename to src/web/auto-reply.broadcast-groups.combined.test.ts index bb609a05c18..40b2f90b22d 100644 --- a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts +++ b/src/web/auto-reply.broadcast-groups.combined.test.ts @@ -18,6 +18,25 @@ installWebAutoReplyTestHomeHooks(); describe("broadcast groups", () => { installWebAutoReplyUnitTestHooks(); + it("skips unknown broadcast agent ids when agents.list is present", async () => { + setLoadConfigMock({ + channels: { whatsapp: { allowFrom: ["*"] } }, + agents: { + defaults: { maxConcurrent: 10 }, + list: [{ id: "alfred" }], + }, + broadcast: { + "+1000": ["alfred", "missing"], + }, + } satisfies OpenClawConfig); + + const { seen, resolver } = await sendWebDirectInboundAndCollectSessionKeys(); + + expect(resolver).toHaveBeenCalledTimes(1); + expect(seen[0]).toContain("agent:alfred:"); + resetLoadConfigMock(); + }); + it("broadcasts sequentially in configured order", async () => { setLoadConfigMock({ channels: { whatsapp: { allowFrom: ["*"] } }, @@ -38,6 +57,7 @@ describe("broadcast groups", () => { expect(seen[1]).toContain("agent:baerbel:"); resetLoadConfigMock(); }); + it("shares group history across broadcast agents and clears after replying", async () => { setLoadConfigMock({ channels: { whatsapp: { allowFrom: ["*"] } }, @@ -89,7 +109,6 @@ describe("broadcast groups", () => { }; expect(payload.Body).toContain("Chat messages since your last reply"); expect(payload.Body).toContain("Alice (+111): hello group"); - // Message id hints are not included in prompts anymore. expect(payload.Body).not.toContain("[message_id:"); expect(payload.Body).toContain("@bot ping"); expect(payload.SenderName).toBe("Bob"); @@ -118,6 +137,7 @@ describe("broadcast groups", () => { resetLoadConfigMock(); }); + it("broadcasts in parallel by default", async () => { setLoadConfigMock({ channels: { whatsapp: { allowFrom: ["*"] } }, diff --git a/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts b/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts deleted file mode 100644 index f13a76444ab..00000000000 --- a/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import "./test-helpers.js"; -import { describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { sendWebDirectInboundAndCollectSessionKeys } from "./auto-reply.broadcast-groups.test-harness.js"; -import { - installWebAutoReplyTestHomeHooks, - installWebAutoReplyUnitTestHooks, - resetLoadConfigMock, - setLoadConfigMock, -} from "./auto-reply.test-harness.js"; - -installWebAutoReplyTestHomeHooks(); - -describe("broadcast groups", () => { - installWebAutoReplyUnitTestHooks(); - - it("skips unknown broadcast agent ids when agents.list is present", async () => { - setLoadConfigMock({ - channels: { whatsapp: { allowFrom: ["*"] } }, - agents: { - defaults: { maxConcurrent: 10 }, - list: [{ id: "alfred" }], - }, - broadcast: { - "+1000": ["alfred", "missing"], - }, - } satisfies OpenClawConfig); - - const { seen, resolver } = await sendWebDirectInboundAndCollectSessionKeys(); - - expect(resolver).toHaveBeenCalledTimes(1); - expect(seen[0]).toContain("agent:alfred:"); - resetLoadConfigMock(); - }); -}); diff --git a/src/web/auto-reply.typing-controller-idle.test.ts b/src/web/auto-reply.typing-controller-idle.test.ts deleted file mode 100644 index 223a2d3ac1b..00000000000 --- a/src/web/auto-reply.typing-controller-idle.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import "./test-helpers.js"; -import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { monitorWebChannel } from "./auto-reply.js"; -import { - createMockWebListener, - installWebAutoReplyTestHomeHooks, - installWebAutoReplyUnitTestHooks, - resetLoadConfigMock, - setLoadConfigMock, -} from "./auto-reply.test-harness.js"; - -installWebAutoReplyTestHomeHooks(); - -describe("typing controller idle", () => { - installWebAutoReplyUnitTestHooks(); - - it("marks dispatch idle after replies flush", async () => { - const markDispatchIdle = vi.fn(); - const typingMock = { - onReplyStart: vi.fn(async () => {}), - startTypingLoop: vi.fn(async () => {}), - startTypingOnText: vi.fn(async () => {}), - refreshTypingTtl: vi.fn(), - isActive: vi.fn(() => false), - markRunComplete: vi.fn(), - markDispatchIdle, - cleanup: vi.fn(), - }; - const reply = vi.fn().mockResolvedValue(undefined); - const sendComposing = vi.fn().mockResolvedValue(undefined); - const sendMedia = vi.fn().mockResolvedValue(undefined); - - const replyResolver = vi.fn().mockImplementation(async (_ctx, opts) => { - opts?.onTypingController?.(typingMock); - return { text: "final reply" }; - }); - - const mockConfig: OpenClawConfig = { - channels: { whatsapp: { allowFrom: ["*"] } }, - }; - - setLoadConfigMock(mockConfig); - - await monitorWebChannel( - false, - async ({ onMessage }) => { - await onMessage({ - id: "m1", - from: "+1000", - conversationId: "+1000", - to: "+2000", - body: "hello", - timestamp: Date.now(), - chatType: "direct", - chatId: "direct:+1000", - accountId: "default", - sendComposing, - reply, - sendMedia, - }); - return createMockWebListener(); - }, - false, - replyResolver, - ); - - resetLoadConfigMock(); - - expect(markDispatchIdle).toHaveBeenCalled(); - }); -}); diff --git a/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts b/src/web/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts similarity index 72% rename from src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts rename to src/web/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts index 678cf0d37c6..97e77f25f3d 100644 --- a/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts +++ b/src/web/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts @@ -1,11 +1,18 @@ +import "./test-helpers.js"; +import crypto from "node:crypto"; +import fs from "node:fs/promises"; import { beforeAll, describe, expect, it, vi } from "vitest"; import { escapeRegExp, formatEnvelopeTimestamp } from "../../test/helpers/envelope-timestamp.js"; +import type { OpenClawConfig } from "../config/config.js"; +import { setLoggerOverride } from "../logging.js"; import { withEnvAsync } from "../test-utils/env.js"; import { + createMockWebListener, createWebListenerFactoryCapture, installWebAutoReplyTestHomeHooks, installWebAutoReplyUnitTestHooks, makeSessionStore, + resetLoadConfigMock, setLoadConfigMock, } from "./auto-reply.test-harness.js"; import type { WebInboundMessage } from "./inbound.js"; @@ -77,10 +84,9 @@ function makeInboundMessage(params: { }; } -describe("web auto-reply", () => { +describe("web auto-reply connection", () => { installWebAutoReplyUnitTestHooks(); - // Ensure test-harness `vi.mock(...)` hooks are registered before importing the module under test. let monitorWebChannel: typeof import("./auto-reply.js").monitorWebChannel; beforeAll(async () => { ({ monitorWebChannel } = await import("./auto-reply.js")); @@ -242,8 +248,6 @@ describe("web auto-reply", () => { const sendComposing = vi.fn(); const sendMedia = vi.fn(); - // The watchdog only needs `lastMessageAt` to be set. Don't await full message - // processing here since it can schedule timers and become flaky under load. void capturedOnMessage?.( makeInboundMessage({ body: "hi", @@ -277,7 +281,7 @@ describe("web auto-reply", () => { it("processes inbound messages without batching and preserves timestamps", async () => { await withEnvAsync({ TZ: "Europe/Vienna" }, async () => { const originalMax = process.getMaxListeners(); - process.setMaxListeners?.(1); // force low to confirm bump + process.setMaxListeners?.(1); const store = await makeSessionStore({ main: { sessionId: "sid", updatedAt: Date.now() }, @@ -304,14 +308,13 @@ describe("web auto-reply", () => { const capturedOnMessage = capture.getOnMessage(); expect(capturedOnMessage).toBeDefined(); - // Two messages from the same sender with fixed timestamps await capturedOnMessage?.( makeInboundMessage({ body: "first", from: "+1", to: "+2", id: "m1", - timestamp: 1735689600000, // Jan 1 2025 00:00:00 UTC + timestamp: 1735689600000, sendComposing, reply, sendMedia, @@ -323,7 +326,7 @@ describe("web auto-reply", () => { from: "+1", to: "+2", id: "m2", - timestamp: 1735693200000, // Jan 1 2025 01:00:00 UTC + timestamp: 1735693200000, sendComposing, reply, sendMedia, @@ -345,13 +348,140 @@ describe("web auto-reply", () => { new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${secondPattern}\\] \\[openclaw\\] second`), ); expect(secondArgs.Body).not.toContain("first"); - - // Max listeners bumped to avoid warnings in multi-instance test runs expect(process.getMaxListeners?.()).toBeGreaterThanOrEqual(50); } finally { process.setMaxListeners?.(originalMax); await store.cleanup(); + resetLoadConfigMock(); } }); }); + + it("emits heartbeat logs with connection metadata", async () => { + vi.useFakeTimers(); + const logPath = `/tmp/openclaw-heartbeat-${crypto.randomUUID()}.log`; + setLoggerOverride({ level: "trace", file: logPath }); + + const runtime = { + log: vi.fn(), + error: vi.fn(), + exit: vi.fn(), + }; + + const controller = new AbortController(); + const listenerFactory = vi.fn(async () => { + const onClose = new Promise(() => { + // never resolves; abort will short-circuit + }); + return { close: vi.fn(), onClose }; + }); + + const run = monitorWebChannel( + false, + listenerFactory as never, + true, + async () => ({ text: "ok" }), + runtime as never, + controller.signal, + { + heartbeatSeconds: 1, + reconnect: { initialMs: 5, maxMs: 5, maxAttempts: 1, factor: 1.1 }, + }, + ); + + await vi.advanceTimersByTimeAsync(1_000); + controller.abort(); + await vi.runAllTimersAsync(); + await run.catch(() => {}); + + const content = await fs.readFile(logPath, "utf-8"); + expect(content).toMatch(/web-heartbeat/); + expect(content).toMatch(/connectionId/); + expect(content).toMatch(/messagesHandled/); + }); + + it("logs outbound replies to file", async () => { + const logPath = `/tmp/openclaw-log-test-${crypto.randomUUID()}.log`; + setLoggerOverride({ level: "trace", file: logPath }); + + const capture = createWebListenerFactoryCapture(); + + const resolver = vi.fn().mockResolvedValue({ text: "auto" }); + await monitorWebChannel(false, capture.listenerFactory as never, false, resolver as never); + const capturedOnMessage = capture.getOnMessage(); + expect(capturedOnMessage).toBeDefined(); + + await capturedOnMessage?.({ + body: "hello", + from: "+1", + conversationId: "+1", + to: "+2", + accountId: "default", + chatType: "direct", + chatId: "+1", + id: "msg1", + sendComposing: vi.fn(), + reply: vi.fn(), + sendMedia: vi.fn(), + }); + + const content = await fs.readFile(logPath, "utf-8"); + expect(content).toMatch(/web-auto-reply/); + expect(content).toMatch(/auto/); + }); + + it("marks dispatch idle after replies flush", async () => { + const markDispatchIdle = vi.fn(); + const typingMock = { + onReplyStart: vi.fn(async () => {}), + startTypingLoop: vi.fn(async () => {}), + startTypingOnText: vi.fn(async () => {}), + refreshTypingTtl: vi.fn(), + isActive: vi.fn(() => false), + markRunComplete: vi.fn(), + markDispatchIdle, + cleanup: vi.fn(), + }; + const reply = vi.fn().mockResolvedValue(undefined); + const sendComposing = vi.fn().mockResolvedValue(undefined); + const sendMedia = vi.fn().mockResolvedValue(undefined); + + const replyResolver = vi.fn().mockImplementation(async (_ctx, opts) => { + opts?.onTypingController?.(typingMock); + return { text: "final reply" }; + }); + + const mockConfig: OpenClawConfig = { + channels: { whatsapp: { allowFrom: ["*"] } }, + }; + + setLoadConfigMock(mockConfig); + + await monitorWebChannel( + false, + async ({ onMessage }) => { + await onMessage({ + id: "m1", + from: "+1000", + conversationId: "+1000", + to: "+2000", + body: "hello", + timestamp: Date.now(), + chatType: "direct", + chatId: "direct:+1000", + accountId: "default", + sendComposing, + reply, + sendMedia, + }); + return createMockWebListener(); + }, + false, + replyResolver, + ); + + resetLoadConfigMock(); + + expect(markDispatchIdle).toHaveBeenCalled(); + }); }); diff --git a/src/web/auto-reply.web-auto-reply.monitor-logging.test.ts b/src/web/auto-reply.web-auto-reply.monitor-logging.test.ts deleted file mode 100644 index 6703ad7f308..00000000000 --- a/src/web/auto-reply.web-auto-reply.monitor-logging.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import crypto from "node:crypto"; -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; -import { setLoggerOverride } from "../logging.js"; -import { - createWebListenerFactoryCapture, - installWebAutoReplyTestHomeHooks, - installWebAutoReplyUnitTestHooks, -} from "./auto-reply.test-harness.js"; -import { monitorWebChannel } from "./auto-reply/monitor.js"; - -installWebAutoReplyTestHomeHooks(); - -describe("web auto-reply monitor logging", () => { - installWebAutoReplyUnitTestHooks(); - - it("emits heartbeat logs with connection metadata", async () => { - vi.useFakeTimers(); - const logPath = `/tmp/openclaw-heartbeat-${crypto.randomUUID()}.log`; - setLoggerOverride({ level: "trace", file: logPath }); - - const runtime = { - log: vi.fn(), - error: vi.fn(), - exit: vi.fn(), - }; - - const controller = new AbortController(); - const listenerFactory = vi.fn(async () => { - const onClose = new Promise(() => { - // never resolves; abort will short-circuit - }); - return { close: vi.fn(), onClose }; - }); - - const run = monitorWebChannel( - false, - listenerFactory as never, - true, - async () => ({ text: "ok" }), - runtime as never, - controller.signal, - { - heartbeatSeconds: 1, - reconnect: { initialMs: 5, maxMs: 5, maxAttempts: 1, factor: 1.1 }, - }, - ); - - await vi.advanceTimersByTimeAsync(1_000); - controller.abort(); - await vi.runAllTimersAsync(); - await run.catch(() => {}); - - const content = await fs.readFile(logPath, "utf-8"); - expect(content).toMatch(/web-heartbeat/); - expect(content).toMatch(/connectionId/); - expect(content).toMatch(/messagesHandled/); - }); - - it("logs outbound replies to file", async () => { - const logPath = `/tmp/openclaw-log-test-${crypto.randomUUID()}.log`; - setLoggerOverride({ level: "trace", file: logPath }); - - const capture = createWebListenerFactoryCapture(); - - const resolver = vi.fn().mockResolvedValue({ text: "auto" }); - await monitorWebChannel(false, capture.listenerFactory as never, false, resolver as never); - const capturedOnMessage = capture.getOnMessage(); - expect(capturedOnMessage).toBeDefined(); - - await capturedOnMessage?.({ - body: "hello", - from: "+1", - conversationId: "+1", - to: "+2", - accountId: "default", - chatType: "direct", - chatId: "+1", - id: "msg1", - sendComposing: vi.fn(), - reply: vi.fn(), - sendMedia: vi.fn(), - }); - - const content = await fs.readFile(logPath, "utf-8"); - expect(content).toMatch(/web-auto-reply/); - expect(content).toMatch(/auto/); - }); -}); diff --git a/vitest.e2e.config.ts b/vitest.e2e.config.ts index 5902f29c278..f21205c1abe 100644 --- a/vitest.e2e.config.ts +++ b/vitest.e2e.config.ts @@ -24,7 +24,7 @@ export default defineConfig({ pool: "vmForks", maxWorkers: e2eWorkers, silent: !verboseE2E, - include: ["test/**/*.e2e.test.ts"], + include: ["test/**/*.e2e.test.ts", "src/**/*.e2e.test.ts"], exclude, }, });