From cd2b51d7a146c38915e74a5559d375b3a5a61c9d Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 10:36:19 -0800 Subject: [PATCH 1/6] add tests --- spec/src/utils/helpers.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/spec/src/utils/helpers.js b/spec/src/utils/helpers.js index da37e9c8..7f4e4462 100644 --- a/spec/src/utils/helpers.js +++ b/spec/src/utils/helpers.js @@ -14,6 +14,7 @@ const { getNavigator, isNil, getWindowLocation, + getCanonicalUrl, dispatchEvent, createCustomEvent, hasOrderIdRecord, @@ -213,6 +214,35 @@ describe('ConstructorIO - Utils - Helpers', () => { }); }); + describe('getCanonicalUrl', () => { + it('Should return the canonical URL from the DOM link element', () => { + const cleanup = jsdom(); + + const canonicalUrl = 'https://constructor.io/products/item'; + const canonicalEle = document.querySelector('[rel=canonical]'); + canonicalEle.setAttribute('href', canonicalUrl); + + expect(getCanonicalUrl()).to.equal(canonicalUrl); + + cleanup(); + }); + + it('Should return a complete URL when given a relative canonical URL', () => { + const cleanup = jsdom(); + + const relativeUrl = '/products/item'; + const canonicalEle = document.querySelector('[rel=canonical]'); + canonicalEle.setAttribute('href', relativeUrl); + + const result = getCanonicalUrl(); + console.log(result); + expect(result).to.include(relativeUrl); + expect(result).to.match(/^https?:\/\//); + + cleanup(); + }); + }); + describe('dispatchEvent', () => { it('Should dispatch an event if in a DOM context', () => { const cleanup = jsdom(); From 026f4353459a4018f83a70ef5314c2fda56c4afe Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 10:36:52 -0800 Subject: [PATCH 2/6] add url validation --- src/utils/helpers.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/utils/helpers.js b/src/utils/helpers.js index f779fcfc..35fa514c 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -100,18 +100,19 @@ const utils = { }, getCanonicalUrl: () => { + let canonicalURL = null; + if (utils.canUseDOM()) { const linkEle = document?.querySelector('link[rel="canonical"]'); - let canonicalURL = null; + const href = linkEle?.getAttribute('href'); - if (linkEle) { - canonicalURL = linkEle.getAttribute('href'); + if (href) { + const url = new URL(href, document.location.href); + canonicalURL = url.toString(); } - - return canonicalURL; } - return null; + return canonicalURL; }, dispatchEvent: (event) => { From fb774bc242b2b590cc666fdd579e3d69a0daab96 Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 10:37:47 -0800 Subject: [PATCH 3/6] try catch --- src/utils/helpers.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/utils/helpers.js b/src/utils/helpers.js index 35fa514c..057745d3 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -102,14 +102,18 @@ const utils = { getCanonicalUrl: () => { let canonicalURL = null; - if (utils.canUseDOM()) { - const linkEle = document?.querySelector('link[rel="canonical"]'); - const href = linkEle?.getAttribute('href'); + try { + if (utils.canUseDOM()) { + const linkEle = document?.querySelector('link[rel="canonical"]'); + const href = linkEle?.getAttribute('href'); - if (href) { - const url = new URL(href, document.location.href); - canonicalURL = url.toString(); + if (href) { + const url = new URL(href, document.location.href); + canonicalURL = url.toString(); + } } + } catch (e) { + // do nothing } return canonicalURL; From 022818475e8974894c597763275e69b7cac52607 Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 10:40:38 -0800 Subject: [PATCH 4/6] remove console log --- spec/src/utils/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/src/utils/helpers.js b/spec/src/utils/helpers.js index 7f4e4462..2774eb17 100644 --- a/spec/src/utils/helpers.js +++ b/spec/src/utils/helpers.js @@ -235,7 +235,6 @@ describe('ConstructorIO - Utils - Helpers', () => { canonicalEle.setAttribute('href', relativeUrl); const result = getCanonicalUrl(); - console.log(result); expect(result).to.include(relativeUrl); expect(result).to.match(/^https?:\/\//); From f0ea0923fb6730cc64792da26d36d048b0819cf3 Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 10:44:50 -0800 Subject: [PATCH 5/6] more tests --- spec/src/utils/helpers.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spec/src/utils/helpers.js b/spec/src/utils/helpers.js index 2774eb17..a038299b 100644 --- a/spec/src/utils/helpers.js +++ b/spec/src/utils/helpers.js @@ -240,6 +240,28 @@ describe('ConstructorIO - Utils - Helpers', () => { cleanup(); }); + + it('Should return null when canonical link element does not exist', () => { + const cleanup = jsdom(); + const canonicalEle = document.querySelector('[rel=canonical]'); + canonicalEle.remove(); + + expect(getCanonicalUrl()).to.be.null; + cleanup(); + }); + + it('Should return null when href attribute is empty', () => { + const cleanup = jsdom(); + const canonicalEle = document.querySelector('[rel=canonical]'); + canonicalEle.setAttribute('href', ''); + + expect(getCanonicalUrl()).to.be.null; + cleanup(); + }); + + it('Should return null when not in a DOM context', () => { + expect(getCanonicalUrl()).to.be.null; + }); }); describe('dispatchEvent', () => { From 8513d4dfb401f8543dfad3a91b376482b6f11f26 Mon Sep 17 00:00:00 2001 From: Stanley Peng Date: Mon, 15 Dec 2025 11:03:29 -0800 Subject: [PATCH 6/6] minor test fix --- spec/src/modules/tracker.js | 83 +++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/spec/src/modules/tracker.js b/spec/src/modules/tracker.js index 6fcd6f22..6b01874b 100644 --- a/spec/src/modules/tracker.js +++ b/spec/src/modules/tracker.js @@ -27,6 +27,7 @@ const testAnalyticsTag = { param1: 'test', param2: 'test2' }; const utmParameters = 'utm_source=attentive&utm_medium=sms&utm_campaign=campaign_1'; const url = `http://localhost.test/path/name?query=term&category=cat&${utmParameters}`; const referrer = 'https://www.google.com/'; +const canonicalUrl = 'https://localhost/'; function validateOriginReferrer(requestParams) { expect(requestParams).to.have.property('origin_referrer').to.contain('localhost.test/path/name'); @@ -201,7 +202,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -490,7 +491,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -1066,7 +1067,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); validateOriginReferrer(requestParams); @@ -1439,7 +1440,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -1850,7 +1851,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -2317,11 +2318,11 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Body - expect(bodyParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(bodyParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(bodyParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -3031,7 +3032,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -3579,7 +3580,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -4168,11 +4169,11 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestQueryParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestQueryParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestQueryParams).to.have.property('document_referrer').to.equal(referrer); // Body - expect(requestBodyParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestBodyParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestBodyParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -4663,7 +4664,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -5373,7 +5374,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -5920,7 +5921,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -6339,7 +6340,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -6754,7 +6755,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -7204,7 +7205,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -7658,7 +7659,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -8158,7 +8159,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -8596,7 +8597,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -9085,7 +9086,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -9400,7 +9401,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -9718,7 +9719,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -10044,7 +10045,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -10388,7 +10389,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -10707,7 +10708,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -11022,7 +11023,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -11337,7 +11338,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -11655,7 +11656,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -11981,7 +11982,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -12325,7 +12326,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -12644,7 +12645,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -12981,7 +12982,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -13310,7 +13311,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -13632,7 +13633,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -13952,7 +13953,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -14273,7 +14274,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -14594,7 +14595,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -14917,7 +14918,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -15240,7 +15241,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { // Request expect(fetchSpy).to.have.been.called; - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); // Response @@ -15537,7 +15538,7 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { expect(requestParams).to.have.property('s'); expect(requestParams).to.have.property('c').to.equal(clientVersion); expect(requestParams).to.have.property('_dt'); - expect(requestParams).to.have.property('canonical_url').to.equal('https://localhost'); + expect(requestParams).to.have.property('canonical_url').to.equal(canonicalUrl); expect(requestParams).to.have.property('document_referrer').to.equal(referrer); expect(requestParams) .to.have.property('banner_ad_id')