diff --git a/lib/web/eventsource/eventsource.js b/lib/web/eventsource/eventsource.js index 02f4d47d006..e6e661b157c 100644 --- a/lib/web/eventsource/eventsource.js +++ b/lib/web/eventsource/eventsource.js @@ -231,12 +231,9 @@ class EventSource extends EventTarget { // 14. Let processEventSourceEndOfBody given response res be the following step: if res is not a network error, then reestablish the connection. const processEventSourceEndOfBody = (response) => { - if (isNetworkError(response)) { - this.dispatchEvent(new Event('error')) - this.close() + if (!isNetworkError(response)) { + return this.#reconnect() } - - this.#reconnect() } // 15. Fetch request, with processResponseEndOfBody set to processEventSourceEndOfBody... diff --git a/lib/web/eventsource/util.js b/lib/web/eventsource/util.js index 727d8660e5f..ee0b4d36df0 100644 --- a/lib/web/eventsource/util.js +++ b/lib/web/eventsource/util.js @@ -26,7 +26,7 @@ function isASCIINumber (value) { // https://github.com/nodejs/undici/issues/2664 function delay (ms) { return new Promise((resolve) => { - setTimeout(resolve, ms).unref() + setTimeout(resolve, ms) }) } diff --git a/test/eventsource/eventsource-connect.js b/test/eventsource/eventsource-connect.js index 018032044fa..41879ef37e4 100644 --- a/test/eventsource/eventsource-connect.js +++ b/test/eventsource/eventsource-connect.js @@ -5,6 +5,7 @@ const events = require('node:events') const http = require('node:http') const { test, describe } = require('node:test') const { EventSource } = require('../../lib/web/eventsource/eventsource') +const { randomInt } = require('node:crypto') describe('EventSource - sending correct request headers', () => { test('should send request with connection keep-alive', async () => { @@ -181,4 +182,21 @@ describe('EventSource - received response must have content-type to be text/even server.close() } }) + + test('should try to connect again if server is unreachable', async () => { + const domain = 'bad.n' + randomInt(1e10).toString(36) + '.proxy' + + const eventSourceInstance = new EventSource(`http://${domain}`) + + const onerrorCalls = [] + eventSourceInstance.onerror = (error) => { + onerrorCalls.push(error) + } + + await new Promise(resolve => setTimeout(resolve, 8000)) + + eventSourceInstance.close() + + assert.strictEqual(onerrorCalls.length, 3) + }) }) diff --git a/test/node-platform-objects.js b/test/node-platform-objects.js index 19e2b01a507..7bc71e8c699 100644 --- a/test/node-platform-objects.js +++ b/test/node-platform-objects.js @@ -18,16 +18,19 @@ test('unserializable web instances should be uncloneable if node exposes the api { Uncloneable: MessageEvent, value: 'dummy event', brand: 'MessageEvent' }, { Uncloneable: CloseEvent, value: 'dummy event', brand: 'CloseEvent' }, { Uncloneable: ErrorEvent, value: 'dummy event', brand: 'ErrorEvent' }, - { Uncloneable: EventSource, value: 'http://localhost', brand: 'EventSource' }, + { Uncloneable: EventSource, value: 'http://localhost', brand: 'EventSource', doneCb: (entity) => entity.close() }, { Uncloneable: Headers, brand: 'Headers' }, { Uncloneable: WebSocket, value: 'http://localhost', brand: 'WebSocket' }, { Uncloneable: Cache, value: kConstruct, brand: 'Cache' }, { Uncloneable: CacheStorage, value: kConstruct, brand: 'CacheStorage' } ] uncloneables.forEach((platformEntity) => { - t.throws(() => structuredClone(new platformEntity.Uncloneable(platformEntity.value)), + const entity = new platformEntity.Uncloneable(platformEntity.value) + t.throws(() => structuredClone(entity), DOMException, `Cloning ${platformEntity.brand} should throw DOMException`) + + platformEntity.doneCb?.(entity) }) } })