diff --git a/src/shared/messaging/port-rpc.ts b/src/shared/messaging/port-rpc.ts index f4bd984a4b2..fb76a095a77 100644 --- a/src/shared/messaging/port-rpc.ts +++ b/src/shared/messaging/port-rpc.ts @@ -236,7 +236,15 @@ export class PortRPC // send the "close" event through the message channel when the window // containing the sending port is unloaded. if (!('onclose' in MessagePort.prototype) || forceUnloadListener) { - this._listeners.add(currentWindow, 'unload', () => { + this._listeners.add(currentWindow, 'unload', event => { + // Ignore custom events which use the same name. This works around an + // issue in VitalSource. + // + // See https://github.com/hypothesis/support/issues/161#issuecomment-2454560641. + if (event instanceof CustomEvent) { + return; + } + if (this._port) { // Send "close" notification directly. This works in Chrome, Firefox and // Safari >= 16. diff --git a/src/shared/messaging/test/port-rpc-test.js b/src/shared/messaging/test/port-rpc-test.js index 6d3bcba68ef..ee579ba1b44 100644 --- a/src/shared/messaging/test/port-rpc-test.js +++ b/src/shared/messaging/test/port-rpc-test.js @@ -260,6 +260,25 @@ describe('PortRPC', () => { assert.calledWith(closeHandler); }); + // See https://github.com/hypothesis/support/issues/161#issuecomment-2454560641 + it('ignores "fake" window unload events', async () => { + const { port1, port2 } = new MessageChannel(); + const sender = new PortRPC({ forceUnloadListener: true }); + const receiver = new PortRPC(); + const closeHandler = sinon.stub(); + + receiver.on('close', closeHandler); + receiver.connect(port2); + sender.connect(port1); + await waitForMessageDelivery(); + + assert.notCalled(closeHandler); + window.dispatchEvent(new CustomEvent('unload')); + await waitForMessageDelivery(); + + assert.notCalled(closeHandler); + }); + it('should send "close" event when MessagePort emits "close" event', async () => { const { port1, port2 } = new MessageChannel(); const sender = new PortRPC();