1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

[EC-598] feat: add ability to throw errors across messenger

This commit is contained in:
Andreas Coroiu
2023-01-27 16:02:13 +01:00
parent 3c5900250d
commit 547c29970d
3 changed files with 50 additions and 21 deletions

View File

@@ -14,6 +14,7 @@ export enum MessageType {
CredentialGetResponse, CredentialGetResponse,
AbortRequest, AbortRequest,
AbortResponse, AbortResponse,
ErrorResponse,
} }
export type CredentialCreationRequest = { export type CredentialCreationRequest = {
@@ -43,6 +44,11 @@ export type AbortRequest = {
abortedRequestId: string; abortedRequestId: string;
}; };
export type ErrorResponse = {
type: MessageType.ErrorResponse;
error: string;
};
export type AbortResponse = { export type AbortResponse = {
type: MessageType.AbortResponse; type: MessageType.AbortResponse;
abortedRequestId: string; abortedRequestId: string;
@@ -54,4 +60,5 @@ export type Message =
| CredentialGetRequest | CredentialGetRequest
| CredentialGetResponse | CredentialGetResponse
| AbortRequest | AbortRequest
| AbortResponse; | AbortResponse
| ErrorResponse;

View File

@@ -44,6 +44,17 @@ describe("Messenger", () => {
expect(returned).toMatchObject(response); expect(returned).toMatchObject(response);
}); });
it("should throw error from B when sending request from A that fails", async () => {
const request = createRequest();
const error = new Error("Test error");
const requestPromise = messengerA.request(request);
const received = handlerB.recieve();
received[0].reject(error);
await expect(requestPromise).rejects.toThrow();
});
it("should deliver abort signal to B when requesting abort", () => { it("should deliver abort signal to B when requesting abort", () => {
const abortController = new AbortController(); const abortController = new AbortController();
messengerA.request(createRequest(), abortController); messengerA.request(createRequest(), abortController);
@@ -53,15 +64,6 @@ describe("Messenger", () => {
expect(received[0].abortController.signal.aborted).toBe(true); expect(received[0].abortController.signal.aborted).toBe(true);
}); });
it.skip("should abort request and throw error when abort is requested from A", () => {
const abortController = new AbortController();
const requestPromise = messengerA.request(createRequest(), abortController);
abortController.abort();
expect(requestPromise).toThrow();
});
}); });
type TestMessage = Message & { testId: string }; type TestMessage = Message & { testId: string };
@@ -105,6 +107,7 @@ class TestMessageHandler {
private recievedMessages: { private recievedMessages: {
message: TestMessage; message: TestMessage;
respond: (response: TestMessage) => void; respond: (response: TestMessage) => void;
reject: (error: Error) => void;
abortController?: AbortController; abortController?: AbortController;
}[] = []; }[] = [];
@@ -115,6 +118,7 @@ class TestMessageHandler {
message, message,
abortController, abortController,
respond: (response) => resolve(response), respond: (response) => resolve(response),
reject: (error) => reject(error),
}); });
}); });
} }

View File

@@ -49,15 +49,26 @@ export class Messenger {
const abortController = new AbortController(); const abortController = new AbortController();
this.abortControllers.set(message.metadata.requestId, abortController); this.abortControllers.set(message.metadata.requestId, abortController);
const handlerResponse = await this.handler(message, abortController);
this.abortControllers.delete(message.metadata.requestId);
if (handlerResponse === undefined) { try {
return; const handlerResponse = await this.handler(message, abortController);
if (handlerResponse === undefined) {
return;
}
const metadata: Metadata = { requestId: message.metadata.requestId };
this.channel.postMessage({ ...handlerResponse, metadata });
} catch (error) {
const metadata: Metadata = { requestId: message.metadata.requestId };
this.channel.postMessage({
type: MessageType.ErrorResponse,
metadata,
error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
});
} finally {
this.abortControllers.delete(message.metadata.requestId);
} }
const metadata: Metadata = { requestId: message.metadata.requestId };
this.channel.postMessage({ ...handlerResponse, metadata });
}) })
) )
.subscribe(); .subscribe();
@@ -71,7 +82,7 @@ export class Messenger {
}); });
} }
request(request: Message, abortController?: AbortController): Promise<Message> { async request(request: Message, abortController?: AbortController): Promise<Message> {
const requestId = Date.now().toString(); const requestId = Date.now().toString();
const metadata: Metadata = { requestId }; const metadata: Metadata = { requestId };
@@ -93,8 +104,15 @@ export class Messenger {
this.channel.postMessage({ ...request, metadata }); this.channel.postMessage({ ...request, metadata });
return promise.finally(() => const response = await promise;
abortController?.signal.removeEventListener("abort", abortListener) abortController?.signal.removeEventListener("abort", abortListener);
);
if (response.type === MessageType.ErrorResponse) {
const error = new Error();
Object.assign(error, JSON.parse(response.error));
throw error;
}
return response;
} }
} }