From c12500cf5080fe69f4a156715c7aab9f5e77cc4b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 21:16:24 +0100 Subject: [PATCH] test: share qa channel harness --- extensions/qa-channel/src/channel.test.ts | 138 +++++++++------------- 1 file changed, 56 insertions(+), 82 deletions(-) diff --git a/extensions/qa-channel/src/channel.test.ts b/extensions/qa-channel/src/channel.test.ts index e9c8afad980..09793f4c510 100644 --- a/extensions/qa-channel/src/channel.test.ts +++ b/extensions/qa-channel/src/channel.test.ts @@ -83,44 +83,62 @@ function createMockQaRuntime(params?: { } as unknown as PluginRuntime; } +function createQaChannelConfig(params: { baseUrl: string; allowFrom?: string[] }) { + return { + channels: { + "qa-channel": { + baseUrl: params.baseUrl, + botUserId: "openclaw", + botDisplayName: "OpenClaw QA", + allowFrom: params.allowFrom, + }, + }, + }; +} + +async function startQaChannelTestHarness(params?: { + runtime?: PluginRuntime; + allowFrom?: string[]; +}) { + installQaChannelTestRegistry(); + const state = createQaBusState(); + const bus = await startQaBusServer({ state }); + setQaChannelRuntime(params?.runtime ?? createMockQaRuntime()); + const cfg = createQaChannelConfig({ baseUrl: bus.baseUrl, allowFrom: params?.allowFrom }); + const account = qaChannelPlugin.config.resolveAccount(cfg, "default"); + const abort = new AbortController(); + const startAccount = qaChannelPlugin.gateway?.startAccount; + expect(startAccount).toBeDefined(); + const task = startAccount!( + createStartAccountContext({ + account, + cfg, + abortSignal: abort.signal, + }), + ); + return { + state, + async stop() { + abort.abort(); + await task; + await bus.stop(); + }, + }; +} + describe("qa-channel plugin", () => { it("roundtrips inbound DM traffic through the qa bus", { timeout: 20_000 }, async () => { - installQaChannelTestRegistry(); - const state = createQaBusState(); - const bus = await startQaBusServer({ state }); - setQaChannelRuntime(createMockQaRuntime()); - - const cfg = { - channels: { - "qa-channel": { - baseUrl: bus.baseUrl, - botUserId: "openclaw", - botDisplayName: "OpenClaw QA", - allowFrom: ["*"], - }, - }, - }; - const account = qaChannelPlugin.config.resolveAccount(cfg, "default"); - const abort = new AbortController(); - const startAccount = qaChannelPlugin.gateway?.startAccount; - expect(startAccount).toBeDefined(); - const task = startAccount!( - createStartAccountContext({ - account, - cfg, - abortSignal: abort.signal, - }), - ); + const harness = await startQaChannelTestHarness({ allowFrom: ["*"] }); try { - state.addInboundMessage({ + harness.state.addInboundMessage({ conversation: { id: "alice", kind: "direct" }, senderId: "alice", senderName: "Alice", text: "hello", }); - const outbound = await state.waitFor({ + const outbound = await harness.state.waitFor({ kind: "message-text", textIncludes: "qa-echo: hello", direction: "outbound", @@ -128,49 +146,23 @@ describe("qa-channel plugin", () => { }); expect("text" in outbound && outbound.text).toContain("qa-echo: hello"); } finally { - abort.abort(); - await task; - await bus.stop(); + await harness.stop(); } }); it("stages inbound image attachments into agent media payload", { timeout: 20_000 }, async () => { - installQaChannelTestRegistry(); - const state = createQaBusState(); - const bus = await startQaBusServer({ state }); let dispatchedCtx: Record | null = null; - setQaChannelRuntime( - createMockQaRuntime({ + const harness = await startQaChannelTestHarness({ + allowFrom: ["*"], + runtime: createMockQaRuntime({ onDispatch: (ctx) => { dispatchedCtx = ctx; }, }), - ); - - const cfg = { - channels: { - "qa-channel": { - baseUrl: bus.baseUrl, - botUserId: "openclaw", - botDisplayName: "OpenClaw QA", - allowFrom: ["*"], - }, - }, - }; - const account = qaChannelPlugin.config.resolveAccount(cfg, "default"); - const abort = new AbortController(); - const startAccount = qaChannelPlugin.gateway?.startAccount; - expect(startAccount).toBeDefined(); - const task = startAccount!( - createStartAccountContext({ - account, - cfg, - abortSignal: abort.signal, - }), - ); + }); try { - state.addInboundMessage({ + harness.state.addInboundMessage({ conversation: { id: "alice", kind: "direct" }, senderId: "alice", senderName: "Alice", @@ -187,7 +179,7 @@ describe("qa-channel plugin", () => { ], }); - await state.waitFor({ + await harness.state.waitFor({ kind: "message-text", textIncludes: "qa-echo: describe this image", direction: "outbound", @@ -209,9 +201,7 @@ describe("qa-channel plugin", () => { expect(mediaCtx.MediaPaths).toEqual([mediaCtx.MediaPath]); expect(mediaCtx.MediaTypes).toEqual(["image/png"]); } finally { - abort.abort(); - await task; - await bus.stop(); + await harness.stop(); } }); @@ -221,15 +211,7 @@ describe("qa-channel plugin", () => { const bus = await startQaBusServer({ state }); try { - const cfg = { - channels: { - "qa-channel": { - baseUrl: bus.baseUrl, - botUserId: "openclaw", - botDisplayName: "OpenClaw QA", - }, - }, - }; + const cfg = createQaChannelConfig({ baseUrl: bus.baseUrl }); const handleAction = qaChannelPlugin.actions?.handleAction; expect(handleAction).toBeDefined(); @@ -328,15 +310,7 @@ describe("qa-channel plugin", () => { const bus = await startQaBusServer({ state }); try { - const cfg = { - channels: { - "qa-channel": { - baseUrl: bus.baseUrl, - botUserId: "openclaw", - botDisplayName: "OpenClaw QA", - }, - }, - }; + const cfg = createQaChannelConfig({ baseUrl: bus.baseUrl }); const sendTarget = qaChannelPlugin.actions?.extractToolSend?.({ args: {