diff --git a/lib/web/websocket/connection.js b/lib/web/websocket/connection.js index 4ecc8a195fc..aa5d0070e7c 100644 --- a/lib/web/websocket/connection.js +++ b/lib/web/websocket/connection.js @@ -314,6 +314,8 @@ function failWebsocketConnection (handler, code, reason, cause) { handler.controller.abort() + handler.closeReason = reason + if (isConnecting(handler.readyState)) { // If the connection was not established, we must still emit an 'error' and 'close' events handler.onSocketClose() diff --git a/lib/web/websocket/websocket.js b/lib/web/websocket/websocket.js index a2abd9c9ab6..5f27a71c798 100644 --- a/lib/web/websocket/websocket.js +++ b/lib/web/websocket/websocket.js @@ -52,6 +52,7 @@ function getSocketAddress (socket) { * @property {number} readyState * @property {import('stream').Duplex} socket * @property {Set} closeState + * @property {string} [closeReason] * @property {import('../fetch/index').Fetch} controller * @property {boolean} [wasEverConnected=false] */ @@ -113,6 +114,7 @@ class WebSocket extends EventTarget { readyState: states.CONNECTING, socket: null, closeState: new Set(), + closeReason: '', controller: null, wasEverConnected: false } @@ -579,7 +581,7 @@ class WebSocket extends EventTarget { this.#handler.closeState.has(sentCloseFrameState.RECEIVED) let code = 1005 - let reason = '' + let reason = this.#handler.closeReason ?? '' const result = this.#parser?.closingInfo @@ -604,7 +606,8 @@ class WebSocket extends EventTarget { code = 1006 fireEvent('error', this, (type, init) => new ErrorEvent(type, init), { - error: new TypeError(reason) + error: new TypeError(reason), + message: reason }) } diff --git a/test/websocket/issue-4735.js b/test/websocket/issue-4735.js new file mode 100644 index 00000000000..f6ad2346a8e --- /dev/null +++ b/test/websocket/issue-4735.js @@ -0,0 +1,18 @@ +'use strict' + +const { test } = require('node:test') +const { WebSocket } = require('../..') +const { once } = require('node:events') + +test('WebSocket emits error with message when connection cannot be opened', async (t) => { + t.plan(2) + + const ws = new WebSocket('ws://localhost:1') + + ws.addEventListener('error', ({ error, message }) => { + t.assert.strictEqual(error.message, 'Received network error or non-101 status code.') + t.assert.strictEqual(message, 'Received network error or non-101 status code.') + }) + + await once(ws, 'close') +})