From 2b8ec9c796dda93af25fbe4778824e491ee0e521 Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:09:43 +0200 Subject: [PATCH 1/3] docs(http_fetcher): update JSDoc to reflect 304 as successful response --- js/http_fetcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/http_fetcher.js b/js/http_fetcher.js index b2d7b8c083..ef5d36b493 100644 --- a/js/http_fetcher.js +++ b/js/http_fetcher.js @@ -32,7 +32,7 @@ const ERROR_TYPE_TO_TRANSLATION = { * - Authentication support (Basic, Bearer) * - Self-signed certificate support * @augments EventEmitter - * @fires HTTPFetcher#response - When fetch succeeds with ok response + * @fires HTTPFetcher#response - When fetch succeeds (including 304 Not Modified) * @fires HTTPFetcher#error - When fetch fails or returns non-ok response * @example * const fetcher = new HTTPFetcher(url, { reloadInterval: 60000 }); @@ -305,7 +305,7 @@ class HTTPFetcher extends EventEmitter { this.networkErrorCount = 0; /** - * Response event - fired when fetch succeeds + * Response event - fired when fetch succeeds (including 304) * @event HTTPFetcher#response * @type {Response} */ From 6213cf3e6ce812e210541b107ee8135d08e31b2f Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:09:44 +0200 Subject: [PATCH 2/3] test(http_fetcher): move and improve 304 test Moves the 304 test from "Basic fetch operations" to the dedicated "HTTP status code handling > 304 Not Modified" block. Also adds an errorSpy to verify that no error event is emitted alongside the response. --- tests/unit/functions/http_fetcher_spec.js | 53 ++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/tests/unit/functions/http_fetcher_spec.js b/tests/unit/functions/http_fetcher_spec.js index 122025a26c..5162fb760a 100644 --- a/tests/unit/functions/http_fetcher_spec.js +++ b/tests/unit/functions/http_fetcher_spec.js @@ -51,31 +51,6 @@ describe("HTTPFetcher", () => { expect(text).toBe(responseData); }); - it("should treat 304 responses as successful and reset error counters", async () => { - server.use( - http.get(TEST_URL, () => { - return new HttpResponse(null, { status: 304 }); - }) - ); - - fetcher = new HTTPFetcher(TEST_URL, { reloadInterval: 60000 }); - fetcher.serverErrorCount = 2; - fetcher.networkErrorCount = 3; - - const responsePromise = new Promise((resolve) => { - fetcher.on("response", (response) => { - resolve(response); - }); - }); - - fetcher.startPeriodicFetch(); - const response = await responsePromise; - - expect(response.status).toBe(304); - expect(fetcher.serverErrorCount).toBe(0); - expect(fetcher.networkErrorCount).toBe(0); - }); - it("should emit error event on network failure", async () => { server.use( http.get(TEST_URL, () => { @@ -126,6 +101,34 @@ describe("HTTPFetcher", () => { }); describe("HTTPFetcher - HTTP status code handling", () => { + describe("304 Not Modified", () => { + it("should emit response event for 304 and not emit error", async () => { + server.use( + http.get(TEST_URL, () => { + return new HttpResponse(null, { status: 304 }); + }) + ); + + fetcher = new HTTPFetcher(TEST_URL, { reloadInterval: 60000 }); + fetcher.serverErrorCount = 2; + fetcher.networkErrorCount = 3; + + const responsePromise = new Promise((resolve) => { + fetcher.on("response", resolve); + }); + const errorSpy = vi.fn(); + fetcher.on("error", errorSpy); + + fetcher.startPeriodicFetch(); + const response = await responsePromise; + + expect(response.status).toBe(304); + expect(errorSpy).not.toHaveBeenCalled(); + expect(fetcher.serverErrorCount).toBe(0); + expect(fetcher.networkErrorCount).toBe(0); + }); + }); + describe("401/403 errors (Auth failures)", () => { it("should emit error with AUTH_FAILURE for 401", async () => { server.use( From 22a1447f987c7c70fef0852877de8b1163cd873f Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:09:44 +0200 Subject: [PATCH 3/3] refactor(http_fetcher): check success before error in fetch() Happy path first: readers see the emit-response path before error handling. --- js/http_fetcher.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/http_fetcher.js b/js/http_fetcher.js index ef5d36b493..eca4896080 100644 --- a/js/http_fetcher.js +++ b/js/http_fetcher.js @@ -295,11 +295,7 @@ class HTTPFetcher extends EventEmitter { const isSuccessfulResponse = response.ok || response.status === 304; - if (!isSuccessfulResponse) { - const { delay, errorInfo } = this.#getDelayForResponse(response); - nextDelay = delay; - this.emit("error", errorInfo); - } else { + if (isSuccessfulResponse) { // Reset error counts on success this.serverErrorCount = 0; this.networkErrorCount = 0; @@ -310,6 +306,10 @@ class HTTPFetcher extends EventEmitter { * @type {Response} */ this.emit("response", response); + } else { + const { delay, errorInfo } = this.#getDelayForResponse(response); + nextDelay = delay; + this.emit("error", errorInfo); } } catch (error) { const isTimeout = error.name === "AbortError";