From 21ba0fb8a4e4304284169fec11527d57674d446e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 30 Nov 2025 18:00:57 +0000 Subject: [PATCH] Fix test isolation to prevent loading real user config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests were picking up real ~/.warelay/warelay.json with emojis and prefixes (like "🦞"), causing test assertions to fail. Added proper config mocks to all test files. Changes: - Mock loadConfig() in index.core.test.ts, inbound.media.test.ts, monitor-inbox.test.ts - Update test-helpers.ts default mock to disable all prefixes - Tests now use clean config: no messagePrefix, no responsePrefix, no timestamp, allowFrom=["*"] This ensures tests validate core behavior without user-specific config. The responsePrefix feature itself is already fully config-driven - this only fixes test isolation. --- CHANGELOG.md | 3 +++ src/index.core.test.ts | 12 ++++++++++++ src/web/inbound.media.test.ts | 3 +++ src/web/monitor-inbox.test.ts | 3 +++ src/web/test-helpers.ts | 18 ++++++++++++++++-- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc3b329cd..e68934d8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## 1.2.3 — Unreleased ### Changes +- **Auto-recovery from stuck WhatsApp sessions:** Added watchdog timer that detects when WhatsApp event emitter stops firing (e.g., after Bad MAC decryption errors) and automatically restarts the connection after 10 minutes of no message activity. Heartbeat logging now includes `minutesSinceLastMessage` and warns when >30 minutes without messages. +- **Early allowFrom filtering:** Unauthorized senders are now blocked in `inbound.ts` BEFORE encryption/decryption attempts, preventing Bad MAC errors from corrupting session state. Previously, messages from unauthorized senders would trigger decryption failures that could silently kill the event emitter. +- **Test isolation improvements:** Mock `loadConfig()` in all test files to prevent loading real user config (with emojis/prefixes) during tests. Default test config now has no prefixes/timestamps for cleaner assertions. - **Same-phone mode (self-messaging):** warelay now supports running on the same phone number you message from. This enables setups where you chat with yourself to control an AI assistant. Same-phone mode (`from === to`) is always allowed, even without configuring `allowFrom`. Echo detection prevents infinite loops by tracking recently sent message text and skipping auto-replies when incoming messages match. - **Echo detection:** The `fromMe` filter in `inbound.ts` is deliberately removed for same-phone setups; instead, text-based echo detection in `auto-reply.ts` tracks sent messages in a bounded Set (max 100 entries) and skips processing when a match is found. - **Same-phone detection logging:** Verbose mode now logs `📱 Same-phone mode detected` when `from === to`. diff --git a/src/index.core.test.ts b/src/index.core.test.ts index a6c7768c5..63093b801 100644 --- a/src/index.core.test.ts +++ b/src/index.core.test.ts @@ -9,6 +9,18 @@ import { createMockTwilio } from "../test/mocks/twilio.js"; import * as exec from "./process/exec.js"; import { withWhatsAppPrefix } from "./utils.js"; +// Mock config to avoid loading real user config +vi.mock("../src/config/config.js", () => ({ + loadConfig: vi.fn().mockReturnValue({ + inbound: { + allowFrom: ["*"], + messagePrefix: undefined, + responsePrefix: undefined, + timestampPrefix: false, + }, + }), +})); + // Twilio mock factory shared across tests vi.mock("twilio", () => { const { factory } = createMockTwilio(); diff --git a/src/web/inbound.media.test.ts b/src/web/inbound.media.test.ts index fe234953f..f0205b27e 100644 --- a/src/web/inbound.media.test.ts +++ b/src/web/inbound.media.test.ts @@ -9,6 +9,9 @@ vi.mock("../config/config.js", () => ({ loadConfig: vi.fn().mockReturnValue({ inbound: { allowFrom: ["*"], // Allow all in tests + messagePrefix: undefined, + responsePrefix: undefined, + timestampPrefix: false, }, }), })); diff --git a/src/web/monitor-inbox.test.ts b/src/web/monitor-inbox.test.ts index b37398d92..10e312691 100644 --- a/src/web/monitor-inbox.test.ts +++ b/src/web/monitor-inbox.test.ts @@ -13,6 +13,9 @@ vi.mock("../config/config.js", () => ({ loadConfig: vi.fn().mockReturnValue({ inbound: { allowFrom: ["*"], // Allow all in tests + messagePrefix: undefined, + responsePrefix: undefined, + timestampPrefix: false, }, }), })); diff --git a/src/web/test-helpers.ts b/src/web/test-helpers.ts index 2e5856b9d..8a0b02195 100644 --- a/src/web/test-helpers.ts +++ b/src/web/test-helpers.ts @@ -3,14 +3,28 @@ import { vi } from "vitest"; import type { MockBaileysSocket } from "../../test/mocks/baileys.js"; import { createMockBaileys } from "../../test/mocks/baileys.js"; -let loadConfigMock: () => unknown = () => ({}); +let loadConfigMock: () => unknown = () => ({ + inbound: { + allowFrom: ["*"], // Allow all in tests by default + messagePrefix: undefined, // No message prefix in tests + responsePrefix: undefined, // No response prefix in tests + timestampPrefix: false, // No timestamp in tests + }, +}); export function setLoadConfigMock(fn: () => unknown) { loadConfigMock = fn; } export function resetLoadConfigMock() { - loadConfigMock = () => ({}); + loadConfigMock = () => ({ + inbound: { + allowFrom: ["*"], + messagePrefix: undefined, + responsePrefix: undefined, + timestampPrefix: false, + }, + }); } vi.mock("../config/config.js", () => ({