From 0f875b93a17d6d342ef36e0dc525156d9ac8e192 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Fri, 27 Jan 2023 13:28:54 +0100 Subject: [PATCH] [EC-598] feat: add basic test-case for messenger --- .../webauthn/messaging/messenger.spec.ts | 83 +++++++++++++++++++ .../content/webauthn/messaging/messenger.ts | 8 +- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 apps/browser/src/content/webauthn/messaging/messenger.spec.ts diff --git a/apps/browser/src/content/webauthn/messaging/messenger.spec.ts b/apps/browser/src/content/webauthn/messaging/messenger.spec.ts new file mode 100644 index 00000000000..13d68cd2b19 --- /dev/null +++ b/apps/browser/src/content/webauthn/messaging/messenger.spec.ts @@ -0,0 +1,83 @@ +import { Subject } from "rxjs"; + +import { Utils } from "@bitwarden/common/misc/utils"; + +import { Message } from "./message"; +import { Channel, MessageWithMetadata, Messenger } from "./messenger"; + +describe("Messenger", () => { + let messengerA: Messenger; + let messengerB: Messenger; + let handlerA: TestMessageHandler; + let handlerB: TestMessageHandler; + + beforeEach(() => { + const channelPair = new TestChannelPair(); + messengerA = new Messenger(channelPair.channelA); + messengerB = new Messenger(channelPair.channelB); + + handlerA = new TestMessageHandler(); + handlerB = new TestMessageHandler(); + messengerA.addHandler(handlerA.handler); + messengerB.addHandler(handlerB.handler); + }); + + it("should deliver message to B when sending request to A", () => { + const message = createMessage(); + messengerA.request(message); + + const received = handlerB.recieve(); + + expect(received.length).toBe(1); + expect(received[0].message).toMatchObject(message); + }); +}); + +type TestMessage = Message & { testId: string }; + +function createMessage(): TestMessage { + return { testId: Utils.newGuid(), type: "TestMessage" } as any; +} + +class TestChannelPair { + readonly channelA: Channel; + readonly channelB: Channel; + + constructor() { + const subjectA = new Subject(); + const subjectB = new Subject(); + + this.channelA = { + messages$: subjectA, + postMessage: (message) => subjectB.next(message), + }; + + this.channelB = { + messages$: subjectB, + postMessage: (message) => subjectB.next(message), + }; + } +} + +class TestMessageHandler { + readonly handler: (message: TestMessage) => Promise; + + private recievedMessages: { message: TestMessage; respond: (response: TestMessage) => void }[] = + []; + + constructor() { + this.handler = (message) => + new Promise((resolve, reject) => { + this.recievedMessages.push({ + message, + respond: (response) => resolve(response), + }); + }); + } + + recieve() { + const received = this.recievedMessages; + this.recievedMessages = []; + return received; + } +} diff --git a/apps/browser/src/content/webauthn/messaging/messenger.ts b/apps/browser/src/content/webauthn/messaging/messenger.ts index 9c42d87da5d..29faf617614 100644 --- a/apps/browser/src/content/webauthn/messaging/messenger.ts +++ b/apps/browser/src/content/webauthn/messaging/messenger.ts @@ -4,13 +4,13 @@ import { Message } from "./message"; type PostMessageFunction = (message: MessageWithMetadata) => void; -type Channel = { +export type Channel = { messages$: Observable; postMessage: PostMessageFunction; }; -type Metadata = { requestId: string }; -type MessageWithMetadata = Message & { metadata: Metadata }; +export type Metadata = { requestId: string }; +export type MessageWithMetadata = Message & { metadata: Metadata }; // TODO: This class probably duplicates functionality but I'm not especially familiar with // the inner workings of the browser extension yet. @@ -32,7 +32,7 @@ export class Messenger { }); } - private constructor(private channel: Channel) {} + constructor(private channel: Channel) {} request(request: Message): Promise { const requestId = Date.now().toString();