From 38c93299d65719fa9db6eef69e8112a40f562417 Mon Sep 17 00:00:00 2001 From: mocca102 Date: Tue, 15 Apr 2025 21:42:32 +0200 Subject: [PATCH 1/3] Handle text API responses --- spec/src/modules/tracker.js | 27 ++++++++++++++++++++++++ src/modules/tracker.js | 41 +++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/spec/src/modules/tracker.js b/spec/src/modules/tracker.js index ec358ddb..026b7b29 100644 --- a/spec/src/modules/tracker.js +++ b/spec/src/modules/tracker.js @@ -8143,6 +8143,33 @@ describe('ConstructorIO - Tracker', () => { }); }); + it('Should receive an error message when rate limited (429)', (done) => { + // Create a mock response for 429 error + fetchSpy = sinon.spy(() => Promise.resolve({ + ok: false, + status: 429, + statusText: 'Too Many Requests', + headers: new Map([['content-type', 'application/text']]), + text: () => Promise.resolve('Too many requests'), + })); + + const { tracker } = new ConstructorIO({ + apiKey: testApiKey, + fetch: fetchSpy, + }); + + tracker.trackInputFocus(userParameters); + + tracker.on('error', (response) => { + expect(response).to.have.property('url'); + expect(response).to.have.property('method'); + expect(response).to.have.property('message'); + expect(response.message).to.not.be.undefined; + expect(response.message).to.equal('Too many requests'); + done(); + }); + }); + it('Should receive an error message when making a request to an invalid endpoint', (done) => { const { tracker } = new ConstructorIO({ apiKey: testApiKey, diff --git a/src/modules/tracker.js b/src/modules/tracker.js index 19eef80d..3ef45214 100644 --- a/src/modules/tracker.js +++ b/src/modules/tracker.js @@ -152,19 +152,38 @@ function send(url, userParameters, networkParameters, method = 'GET', body = {}) // Request was successful, but returned a non-2XX status code else { - response.json().then((json) => { - instance.eventemitter.emit('error', { - url, - method, - message: json && json.message, + const contentType = response.headers.get('Content-Type') || ''; + + if (contentType.includes('application/json')) { + response.json().then((json) => { + instance.eventemitter.emit('error', { + url, + method, + message: json && json.message, + }); + }).catch((error) => { + instance.eventemitter.emit('error', { + url, + method, + message: error.type, + }); }); - }).catch((error) => { - instance.eventemitter.emit('error', { - url, - method, - message: error.type, + } else { + // If not JSON, fallback to text + response.text().then((text) => { + instance.eventemitter.emit('error', { + url, + method, + message: text || 'Unknown error message', + }); + }).catch((error) => { + instance.eventemitter.emit('error', { + url, + method, + message: `Error reading text: ${error.message}`, + }); }); - }); + } } }).catch((error) => { instance.eventemitter.emit('error', { From 85b499afba7e6161a7912732658b341b4f503001 Mon Sep 17 00:00:00 2001 From: mocca102 Date: Tue, 15 Apr 2025 21:44:03 +0200 Subject: [PATCH 2/3] update content header in test mockup --- spec/src/modules/tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/src/modules/tracker.js b/spec/src/modules/tracker.js index 026b7b29..314c2fda 100644 --- a/spec/src/modules/tracker.js +++ b/spec/src/modules/tracker.js @@ -8149,7 +8149,7 @@ describe('ConstructorIO - Tracker', () => { ok: false, status: 429, statusText: 'Too Many Requests', - headers: new Map([['content-type', 'application/text']]), + headers: new Map([['content-type', 'text/plain']]), text: () => Promise.resolve('Too many requests'), })); From bd9ae74bac1c740d929c6d7b53c239537814fd62 Mon Sep 17 00:00:00 2001 From: mocca102 Date: Wed, 16 Apr 2025 22:44:57 +0200 Subject: [PATCH 3/3] Refactor emitError --- src/modules/tracker.js | 31 ++++++------------------------- src/utils/helpers.js | 6 ++++++ 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/modules/tracker.js b/src/modules/tracker.js index 3ef45214..7dc73486 100644 --- a/src/modules/tracker.js +++ b/src/modules/tracker.js @@ -139,6 +139,7 @@ function send(url, userParameters, networkParameters, method = 'GET', body = {}) if (request) { const instance = this; + const emitError = helpers.getEmitError(instance, { url, method }); request.then((response) => { // Request was successful, and returned a 2XX status code @@ -156,41 +157,21 @@ function send(url, userParameters, networkParameters, method = 'GET', body = {}) if (contentType.includes('application/json')) { response.json().then((json) => { - instance.eventemitter.emit('error', { - url, - method, - message: json && json.message, - }); + emitError(json && json.message); }).catch((error) => { - instance.eventemitter.emit('error', { - url, - method, - message: error.type, - }); + emitError(error.type); }); } else { // If not JSON, fallback to text response.text().then((text) => { - instance.eventemitter.emit('error', { - url, - method, - message: text || 'Unknown error message', - }); + emitError(text || 'Unknown error message'); }).catch((error) => { - instance.eventemitter.emit('error', { - url, - method, - message: `Error reading text: ${error.message}`, - }); + emitError(`Error reading text: ${error.message}`); }); } } }).catch((error) => { - instance.eventemitter.emit('error', { - url, - method, - message: error.toString(), - }); + emitError(error.toString()); }); } } diff --git a/src/utils/helpers.js b/src/utils/helpers.js index 7184f960..4428e06e 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -134,6 +134,12 @@ const utils = { return url; }, + + getEmitError(instance, { url, method }) { + return function emitError(message) { + instance.eventemitter.emit('error', { url, method, message }); + }; + }, }; module.exports = utils;