From d02fc365b450d9f6697dd560f41df7ea73d4d1a8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 4 Apr 2026 00:11:54 +0100 Subject: [PATCH] test(plugins): drop stale core test files --- src/auto-reply/reply/line-directives.test.ts | 387 ------------------- src/channels/plugins/plugins-channel.test.ts | 61 --- src/commands/signal-install.test.ts | 194 ---------- src/infra/matrix-migration-config.test.ts | 228 ----------- src/test-utils/imessage-test-plugin.test.ts | 20 - 5 files changed, 890 deletions(-) delete mode 100644 src/auto-reply/reply/line-directives.test.ts delete mode 100644 src/channels/plugins/plugins-channel.test.ts delete mode 100644 src/commands/signal-install.test.ts delete mode 100644 src/infra/matrix-migration-config.test.ts delete mode 100644 src/test-utils/imessage-test-plugin.test.ts diff --git a/src/auto-reply/reply/line-directives.test.ts b/src/auto-reply/reply/line-directives.test.ts deleted file mode 100644 index d03dc3b94fb..00000000000 --- a/src/auto-reply/reply/line-directives.test.ts +++ /dev/null @@ -1,387 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { hasLineDirectives, parseLineDirectives } from "./line-directives.js"; - -const getLineData = (result: ReturnType) => - (result.channelData?.line as Record | undefined) ?? {}; - -describe("hasLineDirectives", () => { - it("matches expected detection across directive patterns", () => { - const cases: Array<{ text: string; expected: boolean }> = [ - { text: "Here are options [[quick_replies: A, B, C]]", expected: true }, - { text: "[[location: Place | Address | 35.6 | 139.7]]", expected: true }, - { text: "[[confirm: Continue? | Yes | No]]", expected: true }, - { text: "[[buttons: Menu | Choose | Opt1:data1, Opt2:data2]]", expected: true }, - { text: "Just regular text", expected: false }, - { text: "[[not_a_directive: something]]", expected: false }, - { text: "[[media_player: Song | Artist | Speaker]]", expected: true }, - { text: "[[event: Meeting | Jan 24 | 2pm]]", expected: true }, - { text: "[[agenda: Today | Meeting:9am, Lunch:12pm]]", expected: true }, - { text: "[[device: TV | Room]]", expected: true }, - { text: "[[appletv_remote: Apple TV | Playing]]", expected: true }, - ]; - - for (const testCase of cases) { - expect(hasLineDirectives(testCase.text)).toBe(testCase.expected); - } - }); -}); - -describe("parseLineDirectives", () => { - describe("quick_replies", () => { - it("parses quick replies variants", () => { - const cases: Array<{ - text: string; - channelData?: { line: { quickReplies: string[] } }; - quickReplies: string[]; - outputText?: string; - }> = [ - { - text: "Choose one:\n[[quick_replies: Option A, Option B, Option C]]", - quickReplies: ["Option A", "Option B", "Option C"], - outputText: "Choose one:", - }, - { - text: "Before [[quick_replies: A, B]] After", - quickReplies: ["A", "B"], - outputText: "Before After", - }, - { - text: "Text [[quick_replies: C, D]]", - channelData: { line: { quickReplies: ["A", "B"] } }, - quickReplies: ["A", "B", "C", "D"], - outputText: "Text", - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ - text: testCase.text, - channelData: testCase.channelData, - }); - expect(getLineData(result).quickReplies).toEqual(testCase.quickReplies); - if (testCase.outputText !== undefined) { - expect(result.text).toBe(testCase.outputText); - } - } - }); - }); - - describe("location", () => { - it("parses location variants", () => { - const existing = { title: "Existing", address: "Addr", latitude: 1, longitude: 2 }; - const cases: Array<{ - text: string; - channelData?: { line: { location: typeof existing } }; - location?: typeof existing; - outputText?: string; - }> = [ - { - text: "Here's the location:\n[[location: Tokyo Station | Tokyo, Japan | 35.6812 | 139.7671]]", - location: { - title: "Tokyo Station", - address: "Tokyo, Japan", - latitude: 35.6812, - longitude: 139.7671, - }, - outputText: "Here's the location:", - }, - { - text: "[[location: Place | Address | invalid | 139.7]]", - location: undefined, - }, - { - text: "[[location: New | New Addr | 35.6 | 139.7]]", - channelData: { line: { location: existing } }, - location: existing, - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ - text: testCase.text, - channelData: testCase.channelData, - }); - expect(getLineData(result).location).toEqual(testCase.location); - if (testCase.outputText !== undefined) { - expect(result.text).toBe(testCase.outputText); - } - } - }); - }); - - describe("confirm", () => { - it("parses confirm directives with default and custom action payloads", () => { - const cases = [ - { - name: "default yes/no data", - text: "[[confirm: Delete this item? | Yes | No]]", - expectedTemplate: { - type: "confirm", - text: "Delete this item?", - confirmLabel: "Yes", - confirmData: "yes", - cancelLabel: "No", - cancelData: "no", - altText: "Delete this item?", - }, - expectedText: undefined, - }, - { - name: "custom action data", - text: "[[confirm: Proceed? | OK:action=confirm | Cancel:action=cancel]]", - expectedTemplate: { - type: "confirm", - text: "Proceed?", - confirmLabel: "OK", - confirmData: "action=confirm", - cancelLabel: "Cancel", - cancelData: "action=cancel", - altText: "Proceed?", - }, - expectedText: undefined, - }, - ] as const; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - expect(getLineData(result).templateMessage, testCase.name).toEqual( - testCase.expectedTemplate, - ); - expect(result.text, testCase.name).toBe(testCase.expectedText); - } - }); - }); - - describe("buttons", () => { - it("parses message/uri/postback button actions and enforces action caps", () => { - const cases = [ - { - name: "message actions", - text: "[[buttons: Menu | Select an option | Help:/help, Status:/status]]", - expectedTemplate: { - type: "buttons", - title: "Menu", - text: "Select an option", - actions: [ - { type: "message", label: "Help", data: "/help" }, - { type: "message", label: "Status", data: "/status" }, - ], - altText: "Menu: Select an option", - }, - }, - { - name: "uri action", - text: "[[buttons: Links | Visit us | Site:https://example.com]]", - expectedFirstAction: { - type: "uri", - label: "Site", - uri: "https://example.com", - }, - }, - { - name: "postback action", - text: "[[buttons: Actions | Choose | Select:action=select&id=1]]", - expectedFirstAction: { - type: "postback", - label: "Select", - data: "action=select&id=1", - }, - }, - { - name: "action cap", - text: "[[buttons: Menu | Text | A:a, B:b, C:c, D:d, E:e, F:f]]", - expectedActionCount: 4, - }, - ] as const; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const templateMessage = getLineData(result).templateMessage as { - type?: string; - actions?: Array>; - }; - expect(templateMessage?.type, testCase.name).toBe("buttons"); - if ("expectedTemplate" in testCase) { - expect(templateMessage, testCase.name).toEqual(testCase.expectedTemplate); - } - if ("expectedFirstAction" in testCase) { - expect(templateMessage?.actions?.[0], testCase.name).toEqual( - testCase.expectedFirstAction, - ); - } - if ("expectedActionCount" in testCase) { - expect(templateMessage?.actions?.length, testCase.name).toBe( - testCase.expectedActionCount, - ); - } - } - }); - }); - - describe("media_player", () => { - it("parses media_player directives across full/minimal/paused variants", () => { - const cases = [ - { - name: "all fields", - text: "Now playing:\n[[media_player: Bohemian Rhapsody | Queen | Speaker | https://example.com/album.jpg | playing]]", - expectedAltText: "🎵 Bohemian Rhapsody - Queen", - expectedText: "Now playing:", - expectFooter: true, - expectBodyContents: false, - }, - { - name: "minimal", - text: "[[media_player: Unknown Track]]", - expectedAltText: "🎵 Unknown Track", - expectedText: undefined, - expectFooter: false, - expectBodyContents: false, - }, - { - name: "paused status", - text: "[[media_player: Song | Artist | Player | | paused]]", - expectedAltText: undefined, - expectedText: undefined, - expectFooter: false, - expectBodyContents: true, - }, - ] as const; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const flexMessage = getLineData(result).flexMessage as { - altText?: string; - contents?: { footer?: { contents?: unknown[] }; body?: { contents?: unknown[] } }; - }; - expect(flexMessage, testCase.name).toBeDefined(); - if (testCase.expectedAltText !== undefined) { - expect(flexMessage?.altText, testCase.name).toBe(testCase.expectedAltText); - } - if (testCase.expectedText !== undefined) { - expect(result.text, testCase.name).toBe(testCase.expectedText); - } - if (testCase.expectFooter) { - expect(flexMessage?.contents?.footer?.contents?.length, testCase.name).toBeGreaterThan(0); - } - if ("expectBodyContents" in testCase && testCase.expectBodyContents) { - expect(flexMessage?.contents?.body?.contents, testCase.name).toBeDefined(); - } - } - }); - }); - - describe("event", () => { - it("parses event variants", () => { - const cases = [ - { - text: "[[event: Team Meeting | January 24, 2026 | 2:00 PM - 3:00 PM | Conference Room A | Discuss Q1 roadmap]]", - altText: "📅 Team Meeting - January 24, 2026 2:00 PM - 3:00 PM", - }, - { - text: "[[event: Birthday Party | March 15]]", - altText: "📅 Birthday Party - March 15", - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const flexMessage = getLineData(result).flexMessage as { altText?: string }; - expect(flexMessage).toBeDefined(); - expect(flexMessage?.altText).toBe(testCase.altText); - } - }); - }); - - describe("agenda", () => { - it("parses agenda variants", () => { - const cases = [ - { - text: "[[agenda: Today's Schedule | Team Meeting:9:00 AM, Lunch:12:00 PM, Review:3:00 PM]]", - altText: "📋 Today's Schedule (3 events)", - }, - { - text: "[[agenda: Tasks | Buy groceries, Call mom, Workout]]", - altText: "📋 Tasks (3 events)", - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const flexMessage = getLineData(result).flexMessage as { altText?: string }; - expect(flexMessage).toBeDefined(); - expect(flexMessage?.altText).toBe(testCase.altText); - } - }); - }); - - describe("device", () => { - it("parses device variants", () => { - const cases = [ - { - text: "[[device: TV | Streaming Box | Playing | Play/Pause:toggle, Menu:menu]]", - altText: "📱 TV: Playing", - }, - { - text: "[[device: Speaker]]", - altText: "📱 Speaker", - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const flexMessage = getLineData(result).flexMessage as { altText?: string }; - expect(flexMessage).toBeDefined(); - expect(flexMessage?.altText).toBe(testCase.altText); - } - }); - }); - - describe("appletv_remote", () => { - it("parses appletv remote variants", () => { - const cases = [ - { - text: "[[appletv_remote: Apple TV | Playing]]", - contains: "Apple TV", - }, - { - text: "[[appletv_remote: Apple TV]]", - contains: undefined, - }, - ]; - - for (const testCase of cases) { - const result = parseLineDirectives({ text: testCase.text }); - const flexMessage = getLineData(result).flexMessage as { altText?: string }; - expect(flexMessage).toBeDefined(); - if (testCase.contains) { - expect(flexMessage?.altText).toContain(testCase.contains); - } - } - }); - }); - - describe("combined directives", () => { - it("handles text with no directives", () => { - const result = parseLineDirectives({ - text: "Just plain text here", - }); - - expect(result.text).toBe("Just plain text here"); - expect(getLineData(result).quickReplies).toBeUndefined(); - expect(getLineData(result).location).toBeUndefined(); - expect(getLineData(result).templateMessage).toBeUndefined(); - }); - - it("preserves other payload fields", () => { - const result = parseLineDirectives({ - text: "Hello [[quick_replies: A, B]]", - mediaUrl: "https://example.com/image.jpg", - replyToId: "msg123", - }); - - expect(result.mediaUrl).toBe("https://example.com/image.jpg"); - expect(result.replyToId).toBe("msg123"); - expect(getLineData(result).quickReplies).toEqual(["A", "B"]); - }); - }); -}); diff --git a/src/channels/plugins/plugins-channel.test.ts b/src/channels/plugins/plugins-channel.test.ts deleted file mode 100644 index 6f45322d6dd..00000000000 --- a/src/channels/plugins/plugins-channel.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { normalizeIMessageMessagingTarget } from "./normalize/imessage.js"; -import { looksLikeSignalTargetId, normalizeSignalMessagingTarget } from "./normalize/signal.js"; - -describe("imessage target normalization", () => { - it("preserves service prefixes for handles", () => { - expect(normalizeIMessageMessagingTarget("sms:+1 (555) 222-3333")).toBe("sms:+15552223333"); - }); - - it("drops service prefixes for chat targets", () => { - expect(normalizeIMessageMessagingTarget("sms:chat_id:123")).toBe("chat_id:123"); - expect(normalizeIMessageMessagingTarget("imessage:CHAT_GUID:abc")).toBe("chat_guid:abc"); - expect(normalizeIMessageMessagingTarget("auto:ChatIdentifier:foo")).toBe("chatidentifier:foo"); - }); -}); - -describe("signal target normalization", () => { - it("normalizes uuid targets by stripping uuid:", () => { - expect(normalizeSignalMessagingTarget("uuid:123E4567-E89B-12D3-A456-426614174000")).toBe( - "123e4567-e89b-12d3-a456-426614174000", - ); - }); - - it("normalizes signal:uuid targets", () => { - expect(normalizeSignalMessagingTarget("signal:uuid:123E4567-E89B-12D3-A456-426614174000")).toBe( - "123e4567-e89b-12d3-a456-426614174000", - ); - }); - - it("preserves case for group targets", () => { - expect( - normalizeSignalMessagingTarget("signal:group:VWATOdKF2hc8zdOS76q9tb0+5BI522e03QLDAq/9yPg="), - ).toBe("group:VWATOdKF2hc8zdOS76q9tb0+5BI522e03QLDAq/9yPg="); - }); - - it("preserves case for base64-like group IDs without signal prefix", () => { - expect( - normalizeSignalMessagingTarget("group:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789+/ABCD="), - ).toBe("group:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789+/ABCD="); - }); - - it("accepts uuid prefixes for target detection", () => { - expect(looksLikeSignalTargetId("uuid:123e4567-e89b-12d3-a456-426614174000")).toBe(true); - expect(looksLikeSignalTargetId("signal:uuid:123e4567-e89b-12d3-a456-426614174000")).toBe(true); - }); - - it("accepts signal-prefixed E.164 targets for detection", () => { - expect(looksLikeSignalTargetId("signal:+15551234567")).toBe(true); - expect(looksLikeSignalTargetId("signal:15551234567")).toBe(true); - }); - - it("accepts compact UUIDs for target detection", () => { - expect(looksLikeSignalTargetId("123e4567e89b12d3a456426614174000")).toBe(true); - expect(looksLikeSignalTargetId("uuid:123e4567e89b12d3a456426614174000")).toBe(true); - }); - - it("rejects invalid uuid prefixes", () => { - expect(looksLikeSignalTargetId("uuid:")).toBe(false); - expect(looksLikeSignalTargetId("uuid:not-a-uuid")).toBe(false); - }); -}); diff --git a/src/commands/signal-install.test.ts b/src/commands/signal-install.test.ts deleted file mode 100644 index a377428de4d..00000000000 --- a/src/commands/signal-install.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import JSZip from "jszip"; -import * as tar from "tar"; -import { describe, expect, it } from "vitest"; -import type { ReleaseAsset } from "./signal-install.js"; -import { extractSignalCliArchive, looksLikeArchive, pickAsset } from "./signal-install.js"; - -// Realistic asset list modelled after an actual signal-cli GitHub release. -const SAMPLE_ASSETS: ReleaseAsset[] = [ - { - name: "signal-cli-0.13.14-Linux-native.tar.gz", - browser_download_url: "https://example.com/linux-native.tar.gz", - }, - { - name: "signal-cli-0.13.14-Linux-native.tar.gz.asc", - browser_download_url: "https://example.com/linux-native.tar.gz.asc", - }, - { - name: "signal-cli-0.13.14-macOS-native.tar.gz", - browser_download_url: "https://example.com/macos-native.tar.gz", - }, - { - name: "signal-cli-0.13.14-macOS-native.tar.gz.asc", - browser_download_url: "https://example.com/macos-native.tar.gz.asc", - }, - { - name: "signal-cli-0.13.14-Windows-native.zip", - browser_download_url: "https://example.com/windows-native.zip", - }, - { - name: "signal-cli-0.13.14-Windows-native.zip.asc", - browser_download_url: "https://example.com/windows-native.zip.asc", - }, - { name: "signal-cli-0.13.14.tar.gz", browser_download_url: "https://example.com/jvm.tar.gz" }, - { - name: "signal-cli-0.13.14.tar.gz.asc", - browser_download_url: "https://example.com/jvm.tar.gz.asc", - }, -]; - -describe("looksLikeArchive", () => { - it("recognises .tar.gz", () => { - expect(looksLikeArchive("foo.tar.gz")).toBe(true); - }); - - it("recognises .tgz", () => { - expect(looksLikeArchive("foo.tgz")).toBe(true); - }); - - it("recognises .zip", () => { - expect(looksLikeArchive("foo.zip")).toBe(true); - }); - - it("rejects signature files", () => { - expect(looksLikeArchive("foo.tar.gz.asc")).toBe(false); - }); - - it("rejects unrelated files", () => { - expect(looksLikeArchive("README.md")).toBe(false); - }); -}); - -describe("pickAsset", () => { - describe("linux", () => { - it("selects the Linux-native asset on x64", () => { - const result = pickAsset(SAMPLE_ASSETS, "linux", "x64"); - expect(result).toBeDefined(); - expect(result!.name).toContain("Linux-native"); - expect(result!.name).toMatch(/\.tar\.gz$/); - }); - - it("returns undefined on arm64 (triggers brew fallback)", () => { - const result = pickAsset(SAMPLE_ASSETS, "linux", "arm64"); - expect(result).toBeUndefined(); - }); - - it("returns undefined on arm (32-bit)", () => { - const result = pickAsset(SAMPLE_ASSETS, "linux", "arm"); - expect(result).toBeUndefined(); - }); - }); - - describe("darwin", () => { - it("selects the macOS-native asset", () => { - const result = pickAsset(SAMPLE_ASSETS, "darwin", "arm64"); - expect(result).toBeDefined(); - expect(result!.name).toContain("macOS-native"); - }); - - it("selects the macOS-native asset on x64", () => { - const result = pickAsset(SAMPLE_ASSETS, "darwin", "x64"); - expect(result).toBeDefined(); - expect(result!.name).toContain("macOS-native"); - }); - }); - - describe("win32", () => { - it("selects the Windows-native asset", () => { - const result = pickAsset(SAMPLE_ASSETS, "win32", "x64"); - expect(result).toBeDefined(); - expect(result!.name).toContain("Windows-native"); - expect(result!.name).toMatch(/\.zip$/); - }); - }); - - describe("edge cases", () => { - it("returns undefined for an empty asset list", () => { - expect(pickAsset([], "linux", "x64")).toBeUndefined(); - }); - - it("skips assets with missing name or url", () => { - const partial: ReleaseAsset[] = [ - { name: "signal-cli.tar.gz" }, - { browser_download_url: "https://example.com/file.tar.gz" }, - ]; - expect(pickAsset(partial, "linux", "x64")).toBeUndefined(); - }); - - it("falls back to first archive for unknown platform", () => { - const result = pickAsset(SAMPLE_ASSETS, "freebsd" as NodeJS.Platform, "x64"); - expect(result).toBeDefined(); - expect(result!.name).toMatch(/\.tar\.gz$/); - }); - - it("never selects .asc signature files", () => { - const result = pickAsset(SAMPLE_ASSETS, "linux", "x64"); - expect(result).toBeDefined(); - expect(result!.name).not.toMatch(/\.asc$/); - }); - }); -}); - -describe("extractSignalCliArchive", () => { - async function withArchiveWorkspace(run: (workDir: string) => Promise) { - const workDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-signal-install-")); - try { - await run(workDir); - } finally { - await fs.rm(workDir, { recursive: true, force: true }).catch(() => undefined); - } - } - - it("rejects zip slip path traversal", async () => { - await withArchiveWorkspace(async (workDir) => { - const archivePath = path.join(workDir, "bad.zip"); - const extractDir = path.join(workDir, "extract"); - await fs.mkdir(extractDir, { recursive: true }); - - const zip = new JSZip(); - zip.file("../pwned.txt", "pwnd"); - await fs.writeFile(archivePath, await zip.generateAsync({ type: "nodebuffer" })); - - await expect(extractSignalCliArchive(archivePath, extractDir, 5_000)).rejects.toThrow( - /(escapes destination|absolute)/i, - ); - }); - }); - - it("extracts zip archives", async () => { - await withArchiveWorkspace(async (workDir) => { - const archivePath = path.join(workDir, "ok.zip"); - const extractDir = path.join(workDir, "extract"); - await fs.mkdir(extractDir, { recursive: true }); - - const zip = new JSZip(); - zip.file("root/signal-cli", "bin"); - await fs.writeFile(archivePath, await zip.generateAsync({ type: "nodebuffer" })); - - await extractSignalCliArchive(archivePath, extractDir, 5_000); - - const extracted = await fs.readFile(path.join(extractDir, "root", "signal-cli"), "utf-8"); - expect(extracted).toBe("bin"); - }); - }); - - it("extracts tar.gz archives", async () => { - await withArchiveWorkspace(async (workDir) => { - const archivePath = path.join(workDir, "ok.tgz"); - const extractDir = path.join(workDir, "extract"); - const rootDir = path.join(workDir, "root"); - await fs.mkdir(rootDir, { recursive: true }); - await fs.writeFile(path.join(rootDir, "signal-cli"), "bin", "utf-8"); - await tar.c({ cwd: workDir, file: archivePath, gzip: true }, ["root"]); - - await fs.mkdir(extractDir, { recursive: true }); - await extractSignalCliArchive(archivePath, extractDir, 5_000); - - const extracted = await fs.readFile(path.join(extractDir, "root", "signal-cli"), "utf-8"); - expect(extracted).toBe("bin"); - }); - }); -}); diff --git a/src/infra/matrix-migration-config.test.ts b/src/infra/matrix-migration-config.test.ts deleted file mode 100644 index 60f7f835cda..00000000000 --- a/src/infra/matrix-migration-config.test.ts +++ /dev/null @@ -1,228 +0,0 @@ -import path from "node:path"; -import { describe, expect, it } from "vitest"; -import { withTempHome } from "../../test/helpers/temp-home.js"; -import type { OpenClawConfig } from "../config/config.js"; -import { resolveMatrixMigrationAccountTarget } from "./matrix-migration-config.js"; -import { - MATRIX_OPS_ACCESS_TOKEN, - MATRIX_OPS_ACCOUNT_ID, - MATRIX_OPS_USER_ID, - MATRIX_TEST_HOMESERVER, - writeMatrixCredentials, -} from "./matrix.test-helpers.js"; - -function resolveOpsTarget(cfg: OpenClawConfig, env = process.env) { - return resolveMatrixMigrationAccountTarget({ - cfg, - env, - accountId: MATRIX_OPS_ACCOUNT_ID, - }); -} - -describe("resolveMatrixMigrationAccountTarget", () => { - it("reuses stored user identity for token-only configs when the access token matches", async () => { - await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - writeMatrixCredentials(stateDir, { - accountId: MATRIX_OPS_ACCOUNT_ID, - deviceId: "DEVICE-OPS", - accessToken: MATRIX_OPS_ACCESS_TOKEN, - }); - - const cfg: OpenClawConfig = { - channels: { - matrix: { - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - accessToken: MATRIX_OPS_ACCESS_TOKEN, - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).not.toBeNull(); - expect(target?.userId).toBe(MATRIX_OPS_USER_ID); - expect(target?.storedDeviceId).toBe("DEVICE-OPS"); - }); - }); - - it("ignores stored device IDs from stale cached Matrix credentials", async () => { - await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - writeMatrixCredentials(stateDir, { - accountId: MATRIX_OPS_ACCOUNT_ID, - userId: "@old-bot:example.org", - accessToken: "tok-old", - deviceId: "DEVICE-OLD", - }); - - const cfg: OpenClawConfig = { - channels: { - matrix: { - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - userId: "@new-bot:example.org", - accessToken: "tok-new", - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).not.toBeNull(); - expect(target?.userId).toBe("@new-bot:example.org"); - expect(target?.accessToken).toBe("tok-new"); - expect(target?.storedDeviceId).toBeNull(); - }); - }); - - it("does not trust stale stored creds on the same homeserver when the token changes", async () => { - await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - writeMatrixCredentials(stateDir, { - accountId: MATRIX_OPS_ACCOUNT_ID, - userId: "@old-bot:example.org", - accessToken: "tok-old", - deviceId: "DEVICE-OLD", - }); - - const cfg: OpenClawConfig = { - channels: { - matrix: { - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - accessToken: "tok-new", - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).toBeNull(); - }); - }); - - it("does not inherit the base userId for non-default token-only accounts", async () => { - await withTempHome(async (home) => { - const stateDir = path.join(home, ".openclaw"); - writeMatrixCredentials(stateDir, { - accountId: MATRIX_OPS_ACCOUNT_ID, - deviceId: "DEVICE-OPS", - accessToken: MATRIX_OPS_ACCESS_TOKEN, - }); - - const cfg: OpenClawConfig = { - channels: { - matrix: { - homeserver: MATRIX_TEST_HOMESERVER, - userId: "@base-bot:example.org", - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - accessToken: MATRIX_OPS_ACCESS_TOKEN, - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).not.toBeNull(); - expect(target?.userId).toBe(MATRIX_OPS_USER_ID); - expect(target?.storedDeviceId).toBe("DEVICE-OPS"); - }); - }); - - it("does not inherit the base access token for non-default accounts", async () => { - await withTempHome(async () => { - const cfg: OpenClawConfig = { - channels: { - matrix: { - homeserver: MATRIX_TEST_HOMESERVER, - userId: "@base-bot:example.org", - accessToken: "tok-base", - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - userId: MATRIX_OPS_USER_ID, - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).toBeNull(); - }); - }); - - it("does not inherit the global Matrix access token for non-default accounts", async () => { - await withTempHome( - async () => { - const cfg: OpenClawConfig = { - channels: { - matrix: { - accounts: { - ops: { - homeserver: MATRIX_TEST_HOMESERVER, - userId: MATRIX_OPS_USER_ID, - }, - }, - }, - }, - }; - - const target = resolveOpsTarget(cfg); - - expect(target).toBeNull(); - }, - { - env: { - MATRIX_ACCESS_TOKEN: "tok-global", - }, - }, - ); - }); - - it("uses the same scoped env token encoding as runtime account auth", async () => { - await withTempHome(async () => { - const cfg: OpenClawConfig = { - channels: { - matrix: { - accounts: { - "ops-prod": {}, - }, - }, - }, - }; - const env = { - MATRIX_OPS_X2D_PROD_HOMESERVER: "https://matrix.example.org", - MATRIX_OPS_X2D_PROD_USER_ID: "@ops-prod:example.org", - MATRIX_OPS_X2D_PROD_ACCESS_TOKEN: "tok-ops-prod", - } as NodeJS.ProcessEnv; - - const target = resolveMatrixMigrationAccountTarget({ - cfg, - env, - accountId: "ops-prod", - }); - - expect(target).not.toBeNull(); - expect(target?.homeserver).toBe("https://matrix.example.org"); - expect(target?.userId).toBe("@ops-prod:example.org"); - expect(target?.accessToken).toBe("tok-ops-prod"); - }); - }); -}); diff --git a/src/test-utils/imessage-test-plugin.test.ts b/src/test-utils/imessage-test-plugin.test.ts deleted file mode 100644 index 0707f84d00c..00000000000 --- a/src/test-utils/imessage-test-plugin.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { afterEach, describe, expect, it } from "vitest"; -import { - listImportedBundledPluginFacadeIds, - resetFacadeRuntimeStateForTest, -} from "../plugin-sdk/facade-runtime.js"; -import { createIMessageTestPlugin } from "./imessage-test-plugin.js"; - -afterEach(() => { - resetFacadeRuntimeStateForTest(); -}); - -describe("createIMessageTestPlugin", () => { - it("does not load the bundled iMessage facade by default", () => { - expect(listImportedBundledPluginFacadeIds()).toEqual([]); - - createIMessageTestPlugin(); - - expect(listImportedBundledPluginFacadeIds()).toEqual([]); - }); -});