From 359a8a13e15f41f80150af3a1e29efb6de5c623d Mon Sep 17 00:00:00 2001 From: Jesper van den Ende Date: Sun, 20 Oct 2024 16:42:45 +0200 Subject: [PATCH] fix(TypedMessenger): Make sure errors while handling received messages are caught correctly --- src/util/TypedMessenger/TypedMessenger.js | 2 +- .../initializeWebSocket.test.js | 26 +++++++++++++++++++ .../TypedMessenger/shared/websockets.js | 8 ++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/util/TypedMessenger/TypedMessenger.js b/src/util/TypedMessenger/TypedMessenger.js index ecde8c3b..79f948ce 100644 --- a/src/util/TypedMessenger/TypedMessenger.js +++ b/src/util/TypedMessenger/TypedMessenger.js @@ -533,7 +533,7 @@ export class TypedMessenger { try { if (typeof message.data == "string") { const parsed = JSON.parse(message.data); - this.handleReceivedMessage(parsed); + await this.handleReceivedMessage(parsed); } } catch (e) { console.error("An error occurred while handling a websocket message.", message.data, e); diff --git a/test/unit/src/util/TypedMessenger/TypedMessenger/initializeWebSocket.test.js b/test/unit/src/util/TypedMessenger/TypedMessenger/initializeWebSocket.test.js index 567c08c5..680c96de 100644 --- a/test/unit/src/util/TypedMessenger/TypedMessenger/initializeWebSocket.test.js +++ b/test/unit/src/util/TypedMessenger/TypedMessenger/initializeWebSocket.test.js @@ -3,6 +3,7 @@ import { TypedMessenger } from "../../../../../../src/util/TypedMessenger/TypedM import { assertSpyCalls, stub } from "std/testing/mock.ts"; import { assertPromiseResolved } from "../../../../../../src/util/asserts.js"; import { createLinkedMessengers, createLinkedWebSockets } from "./shared/websockets.js"; +import { waitForMicrotasks } from "../../../../../../src/util/waitForMicroTasks.js"; Deno.test({ name: "initializeWebSocket()", @@ -78,3 +79,28 @@ Deno.test({ } }, }); + +Deno.test({ + name: "Errors due to websocket closing before a response message is sent are caught", + async fn() { + const consoleSpy = stub(console, "error", () => {}); + + try { + const { socketA, socketB } = createLinkedWebSockets(); + const { messengerB } = createLinkedMessengers(socketA, socketB, { + foo() { + return "foo"; + }, + }, {}); + socketA.close(); + const sendPromise = messengerB.send.foo(); + + await waitForMicrotasks(); + assertSpyCalls(consoleSpy, 1); + assertEquals(consoleSpy.calls[0].args[0], "An error occurred while handling a websocket message."); + await assertPromiseResolved(sendPromise, false); + } finally { + consoleSpy.restore(); + } + }, +}); diff --git a/test/unit/src/util/TypedMessenger/TypedMessenger/shared/websockets.js b/test/unit/src/util/TypedMessenger/TypedMessenger/shared/websockets.js index f8b25b9d..b37b7e32 100644 --- a/test/unit/src/util/TypedMessenger/TypedMessenger/shared/websockets.js +++ b/test/unit/src/util/TypedMessenger/TypedMessenger/shared/websockets.js @@ -14,6 +14,9 @@ class FakeWebSocket extends EventTarget { * @param {string} data */ send(data) { + if (this.#readyState != WebSocket.OPEN) { + throw new DOMException("readyState not OPEN", "InvalidStateError"); + } this.#otherSocket?.dispatchEvent(new MessageEvent("message", { data, })); @@ -24,6 +27,11 @@ class FakeWebSocket extends EventTarget { this.dispatchEvent(new Event("open")); } + close() { + this.#readyState = WebSocket.CLOSED; + this.dispatchEvent(new Event("close")); + } + error() { this.dispatchEvent(new Event("error")); }