diff --git a/extensions/qa-lab/src/bus-state.test.ts b/extensions/qa-lab/src/bus-state.test.ts index 3d1aa92174..9acc89d996 100644 --- a/extensions/qa-lab/src/bus-state.test.ts +++ b/extensions/qa-lab/src/bus-state.test.ts @@ -39,7 +39,8 @@ describe("qa-bus state", () => { state.reactToMessage({ messageId: message.id, - emoji: "white_check_mark", + emoji: "eyes", + senderId: "alice", }); state.editMessage({ messageId: message.id, @@ -49,51 +50,45 @@ describe("qa-bus state", () => { messageId: message.id, }); - const updated = state.readMessage({ messageId: message.id }); - expect(updated.threadId).toBe(thread.id); - expect(updated.reactions).toHaveLength(1); - expect(updated.text).toContain("(edited)"); - expect(updated.deleted).toBe(true); - - const waited = await state.waitFor({ - kind: "thread-id", - threadId: thread.id, - timeoutMs: 50, + const snapshot = state.getSnapshot(); + expect(snapshot.threads).toHaveLength(1); + expect(snapshot.threads[0]).toMatchObject({ + id: thread.id, + conversationId: "qa-room", + title: "QA thread", + }); + expect(snapshot.messages[0]).toMatchObject({ + id: message.id, + text: "inside thread (edited)", + deleted: true, + reactions: [{ emoji: "eyes", senderId: "alice" }], }); - expect("id" in waited && waited.id).toBe(thread.id); }); - it("replays fresh events after a reset rewinds the cursor", () => { + it("waits for a text match and rejects on timeout", async () => { const state = createQaBusState(); - - state.addInboundMessage({ - conversation: { id: "alice", kind: "direct" }, - senderId: "alice", - text: "before reset", - }); - const beforeReset = state.poll({ - accountId: "default", - cursor: 0, - }); - expect(beforeReset.events).toHaveLength(1); - - state.reset(); - state.addInboundMessage({ - conversation: { id: "alice", kind: "direct" }, - senderId: "alice", - text: "after reset", + const pending = state.waitFor({ + kind: "message-text", + textIncludes: "needle", + timeoutMs: 500, }); - const afterReset = state.poll({ - accountId: "default", - cursor: beforeReset.cursor, - }); - expect(afterReset.events).toHaveLength(1); - expect(afterReset.events[0]?.kind).toBe("inbound-message"); - expect( - afterReset.events[0] && - "message" in afterReset.events[0] && - afterReset.events[0].message.text, - ).toBe("after reset"); + setTimeout(() => { + state.addOutboundMessage({ + to: "dm:alice", + text: "haystack + needle", + }); + }, 20); + + const matched = await pending; + expect("text" in matched && matched.text).toContain("needle"); + + await expect( + state.waitFor({ + kind: "message-text", + textIncludes: "missing", + timeoutMs: 20, + }), + ).rejects.toThrow("qa-bus wait timeout"); }); }); diff --git a/scripts/qa-e2e.ts b/scripts/qa-e2e.ts index c329ddccb6..05bf253554 100644 --- a/scripts/qa-e2e.ts +++ b/scripts/qa-e2e.ts @@ -1,4 +1,4 @@ -import { runQaE2eSelfCheck } from "../src/qa-e2e/runner.js"; +import { runQaE2eSelfCheck } from "../extensions/qa-lab/api.js"; const outputPath = process.argv[2]?.trim() || ".artifacts/qa-e2e/self-check.md"; diff --git a/src/cli/qa-cli.ts b/src/cli/qa-cli.ts index f3caf2be8d..e110d63f30 100644 --- a/src/cli/qa-cli.ts +++ b/src/cli/qa-cli.ts @@ -1,5 +1,5 @@ import type { Command } from "commander"; -import { registerQaLabCli } from "../qa-e2e/cli.js"; +import { registerQaLabCli } from "../../extensions/qa-lab/api.js"; export function registerQaCli(program: Command) { registerQaLabCli(program); diff --git a/src/qa-e2e/cli.ts b/src/qa-e2e/cli.ts deleted file mode 100644 index 7e5585eb0c..0000000000 --- a/src/qa-e2e/cli.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerQaLabCli } from "../../extensions/qa-lab/api.js"; diff --git a/src/qa-e2e/runner.ts b/src/qa-e2e/runner.ts deleted file mode 100644 index 57d9d5c96c..0000000000 --- a/src/qa-e2e/runner.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "../../extensions/qa-lab/api.js";