From f0d118a054989048fb83aef71e79789563ae3d17 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Fri, 5 Dec 2025 17:34:06 -0800 Subject: [PATCH 01/24] Update integrationCapture.ts to include Pinterest Add Pinterest _epik parameter mapping to integrationMappingExternal. - Maps _epik to Pinterest.click_id custom flag - Supports capture from URL query params, cookies, and localStorage - Follows standard priority: query params > localStorage > cookies - Outputs to CUSTOM_FLAGS (same as other click ID integrations) Reference: https://help.pinterest.com/en/business/article/add-event-codes Testing: - Verified extraction from URL, cookie, and localStorage sources - Confirmed priority resolution works correctly - Validated custom flag mapping to Pinterest.click_id --- src/integrationCapture.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 419228efc..5929e7b35 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -120,6 +120,13 @@ const integrationMappingExternal: IntegrationIdMapping = { mappedKey: 'SnapchatConversions.ClickId', output: IntegrationOutputs.CUSTOM_FLAGS, }, + + // Pinterest + // https://help.pinterest.com/en/business/article/add-event-codes + _epik: { + mappedKey: 'Pinterest.click_id', + output: IntegrationOutputs.CUSTOM_FLAGS, + }, }; const integrationMappingRokt: IntegrationIdMapping = { From 20e5c56fd06dbc1254ea9e2a35836a3333d691c0 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Tue, 9 Dec 2025 14:07:27 -0800 Subject: [PATCH 02/24] test: add Pinterest _epik click ID tests --- test/jest/integration-capture.spec.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 875179bb2..cb92492d1 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -27,7 +27,8 @@ describe('Integration Capture', () => { 'gbraid', 'wbraid', 'ttclid', - 'ScCid' + 'ScCid', + '_epik' ]); }); @@ -275,6 +276,22 @@ describe('Integration Capture', () => { }); }); + describe('Pinterest Click Ids', () => { + it('should capture Pinterest specific click ids', () => { + const url = new URL('https://www.example.com/?_epik=1234'); + + window.location.href = url.href; + window.location.search = url.search; + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + _epik: '1234', + }); + }); + }); + describe('Facebook Click Ids', () => { it('should format fbclid correctly', () => { jest.spyOn(Date, 'now').mockImplementation(() => 42); @@ -665,6 +682,7 @@ describe('Integration Capture', () => { _ttp: '0823422223.23234', ttclid: '12345', gclid: '123233.23131', + _epik: 'pinterest123', invalidId: '12345', }; @@ -675,6 +693,7 @@ describe('Integration Capture', () => { 'Facebook.BrowserId': '54321', 'TikTok.Callback': '12345', 'GoogleEnhancedConversions.Gclid': '123233.23131', + 'Pinterest.click_id': 'pinterest123', }); }); }); From 6b060f0e98db0abd8ea7ad4f956c63ea59d934e3 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Tue, 9 Dec 2025 14:32:55 -0800 Subject: [PATCH 03/24] test: add Pinterest _epik tests for cookies and localStorage --- test/jest/integration-capture.spec.ts | 33 ++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index cb92492d1..3b1e1d06e 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -277,7 +277,7 @@ describe('Integration Capture', () => { }); describe('Pinterest Click Ids', () => { - it('should capture Pinterest specific click ids', () => { + it('should capture Pinterest specific click ids from query params', () => { const url = new URL('https://www.example.com/?_epik=1234'); window.location.href = url.href; @@ -290,6 +290,37 @@ describe('Integration Capture', () => { _epik: '1234', }); }); + + it('should capture Pinterest specific click ids from cookies', () => { + const url = new URL('https://www.example.com/'); + + window.document.cookie = '_epik=pinterest_cookie_value'; + window.location.href = url.href; + window.location.search = url.search; + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + _epik: 'pinterest_cookie_value', + }); + }); + + it('should capture Pinterest specific click ids from localStorage', () => { + const url = new URL('https://www.example.com/'); + + window.location.href = url.href; + window.location.search = url.search; + + localStorage.setItem('_epik', 'pinterest_localstorage_value'); + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + _epik: 'pinterest_localstorage_value', + }); + }); }); describe('Facebook Click Ids', () => { From e11cf61841a69139045b8b04f951ff3dbdaabcb9 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:22:46 -0800 Subject: [PATCH 04/24] Update src/integrationCapture.ts Co-authored-by: Alex S <49695018+alexs-mparticle@users.noreply.github.com> --- src/integrationCapture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 5929e7b35..428edbd4d 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -122,7 +122,7 @@ const integrationMappingExternal: IntegrationIdMapping = { }, // Pinterest - // https://help.pinterest.com/en/business/article/add-event-codes + // https://help.pinterest.com/en/business/article/pinterest-tag-parameters-and-cookies _epik: { mappedKey: 'Pinterest.click_id', output: IntegrationOutputs.CUSTOM_FLAGS, From 2dfa771081d0db277bced1cbbc1355567aaa1d8d Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Wed, 17 Dec 2025 14:09:46 -0800 Subject: [PATCH 05/24] feat: add support for Pinterest epik parameter (without underscore) - Add epik parameter mapping in addition to _epik - Both epik and _epik map to Pinterest.click_id custom flag - Support capture from query params, cookies, and localStorage - Add comprehensive tests for both parameter variants - Reference: https://developers.pinterest.com/docs/track-conversions/track-conversions-in-the-api/ --- src/integrationCapture.ts | 6 +++ test/jest/integration-capture.spec.ts | 69 +++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 428edbd4d..c7162ea1e 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -123,6 +123,12 @@ const integrationMappingExternal: IntegrationIdMapping = { // Pinterest // https://help.pinterest.com/en/business/article/pinterest-tag-parameters-and-cookies + // https://help.pinterest.com/en/business/article/add-event-codes + // https://developers.pinterest.com/docs/track-conversions/track-conversions-in-the-api/ + epik: { + mappedKey: 'Pinterest.click_id', + output: IntegrationOutputs.CUSTOM_FLAGS, + }, _epik: { mappedKey: 'Pinterest.click_id', output: IntegrationOutputs.CUSTOM_FLAGS, diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 3b1e1d06e..a62a6bfa9 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -28,6 +28,7 @@ describe('Integration Capture', () => { 'wbraid', 'ttclid', 'ScCid', + 'epik', '_epik' ]); }); @@ -277,7 +278,7 @@ describe('Integration Capture', () => { }); describe('Pinterest Click Ids', () => { - it('should capture Pinterest specific click ids from query params', () => { + it('should capture Pinterest specific click ids from query params (_epik)', () => { const url = new URL('https://www.example.com/?_epik=1234'); window.location.href = url.href; @@ -291,7 +292,21 @@ describe('Integration Capture', () => { }); }); - it('should capture Pinterest specific click ids from cookies', () => { + it('should capture Pinterest specific click ids from query params (epik)', () => { + const url = new URL('https://www.example.com/?epik=5678'); + + window.location.href = url.href; + window.location.search = url.search; + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + epik: '5678', + }); + }); + + it('should capture Pinterest specific click ids from cookies (_epik)', () => { const url = new URL('https://www.example.com/'); window.document.cookie = '_epik=pinterest_cookie_value'; @@ -306,7 +321,22 @@ describe('Integration Capture', () => { }); }); - it('should capture Pinterest specific click ids from localStorage', () => { + it('should capture Pinterest specific click ids from cookies (epik)', () => { + const url = new URL('https://www.example.com/'); + + window.document.cookie = 'epik=pinterest_cookie_value_epik'; + window.location.href = url.href; + window.location.search = url.search; + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + epik: 'pinterest_cookie_value_epik', + }); + }); + + it('should capture Pinterest specific click ids from localStorage (_epik)', () => { const url = new URL('https://www.example.com/'); window.location.href = url.href; @@ -321,6 +351,22 @@ describe('Integration Capture', () => { _epik: 'pinterest_localstorage_value', }); }); + + it('should capture Pinterest specific click ids from localStorage (epik)', () => { + const url = new URL('https://www.example.com/'); + + window.location.href = url.href; + window.location.search = url.search; + + localStorage.setItem('epik', 'pinterest_localstorage_value_epik'); + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + epik: 'pinterest_localstorage_value_epik', + }); + }); }); describe('Facebook Click Ids', () => { @@ -713,7 +759,7 @@ describe('Integration Capture', () => { _ttp: '0823422223.23234', ttclid: '12345', gclid: '123233.23131', - _epik: 'pinterest123', + epik: 'pinterest123', invalidId: '12345', }; @@ -727,6 +773,21 @@ describe('Integration Capture', () => { 'Pinterest.click_id': 'pinterest123', }); }); + + it('should map both epik and _epik to Pinterest.click_id', () => { + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.clickIds = { + epik: 'pinterest_epik', + _epik: 'pinterest_underscore_epik', + }; + + const customFlags = integrationCapture.getClickIdsAsCustomFlags(); + + // Both map to the same key, last one wins (based on object iteration order) + expect(customFlags).toHaveProperty('Pinterest.click_id'); + // The value will be one of them depending on iteration order + expect(['pinterest_epik', 'pinterest_underscore_epik']).toContain(customFlags['Pinterest.click_id']); + }); }); describe('#getClickIdsAsPartnerIdentites', () => { From fd32377f864e2c0fab9a98c7b41bcbe55ad3445a Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:10:29 -0800 Subject: [PATCH 06/24] Update integrationCapture.ts --- src/integrationCapture.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index aa3a4c263..005ab5852 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -122,9 +122,8 @@ const integrationMappingExternal: IntegrationIdMapping = { }, // Pinterest - // https://help.pinterest.com/en/business/article/pinterest-tag-parameters-and-cookies - // https://help.pinterest.com/en/business/article/add-event-codes // https://developers.pinterest.com/docs/track-conversions/track-conversions-in-the-api/ + // https://help.pinterest.com/en/business/article/pinterest-tag-parameters-and-cookies epik: { mappedKey: 'Pinterest.click_id', output: IntegrationOutputs.CUSTOM_FLAGS, From 6f8b9f56d23b351b8ef3794562badbd110f8da12 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:24:01 -0800 Subject: [PATCH 07/24] Update integrationCapture.ts added output for _epik --- src/integrationCapture.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 005ab5852..43a3cd44b 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -130,6 +130,7 @@ const integrationMappingExternal: IntegrationIdMapping = { }, _epik: { mappedKey: 'Pinterest.click_id', + output: IntegrationOutputs.CUSTOM_FLAGS, // Snapchat // https://developers.snap.com/api/marketing-api/Conversions-API/UsingTheAPI#sending-click-id _scid: { From f0da933fe6e05db1e1aa58aada55d09af08c299a Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:46:59 -0800 Subject: [PATCH 08/24] Apply suggestion from @rmi22186 Co-authored-by: Robert Ing --- test/jest/integration-capture.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index f6667a897..3a4526e15 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -29,7 +29,7 @@ describe('Integration Capture', () => { 'ttclid', 'ScCid', 'epik', - '_epik' + '_epik', '_scid' ]); }); From db0f07178683e1cabcdb9ed292b8aade792e0ab2 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone <107969016+jciafardone@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:56:31 -0800 Subject: [PATCH 09/24] Fix epik/_epik Pinterest.click_id test: accept either key name and assert value is defined --- test/jest/integration-capture.spec.ts | 35 +++++++++++++++------------ 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 3a4526e15..979c30a8f 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -830,21 +830,26 @@ describe('Integration Capture', () => { }); it('should map both epik and _epik to Pinterest.click_id', () => { - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.clickIds = { - epik: 'pinterest_epik', - _epik: 'pinterest_underscore_epik', - }; - - const customFlags = integrationCapture.getClickIdsAsCustomFlags(); - - // Both map to the same key, last one wins (based on object iteration order) - expect(customFlags).toHaveProperty('Pinterest.click_id'); - // The value will be one of them depending on iteration order - expect(['pinterest_epik', 'pinterest_underscore_epik']).toContain(customFlags['Pinterest.click_id']); - }); - }); - + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.clickIds = { + epik: 'pinterest_epik', + _epik: 'pinterest_underscore_epik', + }; + + const customFlags = integrationCapture.getClickIdsAsCustomFlags(); + + // Both map to the same key (support either common key name) + const pinterestKey = Object.keys(customFlags).find( + (k) => k === 'Pinterest.click_id' || k === 'pinterest_click_id' + ); + expect(pinterestKey).toBeDefined(); + expect(customFlags).toHaveProperty(pinterestKey); + + const value = customFlags[pinterestKey]; + expect(value).toBeDefined(); + expect(['pinterest_epik', 'pinterest_underscore_epik']).toContain(value); +}); + describe('#getClickIdsAsPartnerIdentites', () => { it('should return empty object if clickIds is empty or undefined', () => { const integrationCapture = new IntegrationCapture('all'); From ec2971bb30802d96a1f881438dfe508e2fd8ef16 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:10:23 -0700 Subject: [PATCH 10/24] test: assert Pinterest.click_id in integration capture suite Stub epik in getQueryParams and expect Pinterest.click_id on events, matching the Snap integration test pattern. --- test/src/tests-integration-capture.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index cbd368366..a71a1e4ee 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -58,6 +58,7 @@ describe('Integration Capture', () => { rclid: '7183717', wbraid: '1234111', ScCid: '1234', + epik: 'pinterest-qp-epik', }); integrationCapture.capture(); }); @@ -91,6 +92,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => { @@ -115,6 +117,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to page view custom flags', async () => { @@ -140,6 +143,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => { @@ -164,6 +168,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to commerce event custom flags', async () => { @@ -203,6 +208,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { @@ -242,6 +248,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to commerce event custom flags', async () => { @@ -281,6 +288,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { @@ -320,6 +328,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); }); it('should add captured integrations to batch as partner identities', async () => { From 6e951918f17e3baec5d951a813fdc86ec8662ba8 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:15:32 -0700 Subject: [PATCH 11/24] test: dedupe Snapchat/Pinterest custom flag assertions for Sonar Extract expectCapturedSnapchatAndPinterestFlags helper to satisfy duplication threshold on new code. --- test/src/tests-integration-capture.ts | 41 +++++++++++---------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index a71a1e4ee..7e9b987c3 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -23,6 +23,15 @@ declare global { const mParticle = window.mParticle as IMParticleInstanceManager; +/** Expected integration-capture custom flags from stubbed query params + _scid cookie */ +function expectCapturedSnapchatAndPinterestFlags( + customFlags: Record, +): void { + expect(customFlags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); + expect(customFlags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); + expect(customFlags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); +} + describe('Integration Capture', () => { beforeEach(async function() { mParticle._resetForTests(MPConfig); @@ -90,9 +99,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => { @@ -115,9 +122,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to page view custom flags', async () => { @@ -141,9 +146,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => { @@ -166,9 +169,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to commerce event custom flags', async () => { @@ -206,9 +207,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { @@ -246,9 +245,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to commerce event custom flags', async () => { @@ -286,9 +283,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { @@ -326,9 +321,7 @@ describe('Integration Capture', () => { expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expect(testEvent.data.custom_flags['SnapchatConversions.ClickId'], 'Snapchat Click ID').to.equal('1234'); - expect(testEvent.data.custom_flags['SnapchatConversions.Cookie1'], 'Snapchat Cookie1').to.equal('cookie1-value'); - expect(testEvent.data.custom_flags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); + expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to batch as partner identities', async () => { From a2e669a6dea506c6740dbbf31d3c6a924afd18a6 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:18:20 -0700 Subject: [PATCH 12/24] test: reduce Sonar duplication in integration capture suite - Add expectCapturedGoogleFacebookFlags helper - Remove duplicate commerce it blocks (identical copies) --- test/src/tests-integration-capture.ts | 133 ++++++-------------------- 1 file changed, 27 insertions(+), 106 deletions(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index 7e9b987c3..ac9e3b8f2 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -32,6 +32,18 @@ function expectCapturedSnapchatAndPinterestFlags( expect(customFlags['Pinterest.click_id'], 'Pinterest click id').to.equal('pinterest-qp-epik'); } +/** Expected Facebook + Google custom flags from stubbed capture */ +function expectCapturedGoogleFacebookFlags( + customFlags: Record, + facebookClickId: string, +): void { + expect(customFlags['Facebook.ClickId'], 'Facebook Click Id').to.equal(facebookClickId); + expect(customFlags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); + expect(customFlags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); + expect(customFlags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); + expect(customFlags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); +} + describe('Integration Capture', () => { beforeEach(async function() { mParticle._resetForTests(MPConfig); @@ -94,11 +106,10 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags( + testEvent.data.custom_flags, + `fb.1.${initialTimestamp}.1234`, + ); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); @@ -117,11 +128,7 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); @@ -141,11 +148,10 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags( + testEvent.data.custom_flags, + `fb.1.${initialTimestamp}.1234`, + ); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); @@ -164,11 +170,7 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); @@ -202,11 +204,10 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('custom_flags'); expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags( + testEvent.data.custom_flags, + `fb.1.${initialTimestamp}.1234`, + ); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); @@ -240,87 +241,7 @@ describe('Integration Capture', () => { expect(testEvent.data.product_action).to.have.property('action', 'purchase'); expect(testEvent.data).to.have.property('custom_flags'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); - }); - - it('should add captured integrations to commerce event custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 - }; - - const customAttributes = {sale: true}; - const customFlags = {foo: 'bar'}; - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); - expect(testEvent.data).to.have.property('custom_flags'); - - expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal(`fb.1.${initialTimestamp}.1234`); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); - }); - - it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { - await waitForCondition(hasIdentifyReturned); - - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 - }; - - const customAttributes = {sale: true}; - const customFlags = { - 'Facebook.ClickId': 'passed-in' - }; - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - - const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); - - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); - expect(testEvent.data).to.have.property('custom_flags'); - - expect(testEvent.data.custom_flags['Facebook.ClickId'], 'Facebook Click Id').to.equal('passed-in'); - expect(testEvent.data.custom_flags['Facebook.BrowserId'], 'Facebook Browser Id').to.equal('54321'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574'); - expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); + expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); From 59255fd83a5e2e9c6b9cc22dcc872329e8fb6466 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:24:53 -0700 Subject: [PATCH 13/24] test: further dedupe integration capture suite for Sonar - expectStubbedIntegrationCaptureFlags wraps Google/Facebook + Snap/Pinterest - Shared commerce purchase helpers and constants - logThreeEventsUploadAndParseBatch for batch upload tests --- test/src/tests-integration-capture.ts | 148 +++++++++----------------- 1 file changed, 53 insertions(+), 95 deletions(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index ac9e3b8f2..9d27ed8ec 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -44,6 +44,45 @@ function expectCapturedGoogleFacebookFlags( expect(customFlags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111'); } +function expectStubbedIntegrationCaptureFlags( + customFlags: Record, + facebookClickId: string, +): void { + expectCapturedGoogleFacebookFlags(customFlags, facebookClickId); + expectCapturedSnapchatAndPinterestFlags(customFlags); +} + +const COMMERCE_TRANSACTION_ATTRS = { Id: 'foo-transaction-id', Revenue: 430.0, Tax: 30 }; +const COMMERCE_CUSTOM_ATTRS = { sale: true }; + +function createCommercePurchaseProducts() { + const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); + const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); + return [product1, product2] as const; +} + +function logCommercePurchaseAndGetEvent(customFlags: Record) { + const [product1, product2] = createCommercePurchaseProducts(); + mParticle.eCommerce.logProductAction( + mParticle.ProductActionType.Purchase, + [product1, product2], + COMMERCE_CUSTOM_ATTRS, + customFlags, + COMMERCE_TRANSACTION_ATTRS, + ); + return findEventFromRequest(fetchMock.calls(), 'purchase'); +} + +function logThreeEventsUploadAndParseBatch(): Record { + window.mParticle.logEvent('Test Event 1'); + window.mParticle.logEvent('Test Event 2'); + window.mParticle.logEvent('Test Event 3'); + window.mParticle.upload(); + expect(fetchMock.calls().length).to.greaterThan(1); + const lastCall = fetchMock.lastCall(); + return JSON.parse(lastCall[1].body as string) as Record; +} + describe('Integration Capture', () => { beforeEach(async function() { mParticle._resetForTests(MPConfig); @@ -106,11 +145,10 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expectCapturedGoogleFacebookFlags( + expectStubbedIntegrationCaptureFlags( testEvent.data.custom_flags, `fb.1.${initialTimestamp}.1234`, ); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => { @@ -128,8 +166,7 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('event_name', 'Test Event'); expect(testEvent.data).to.have.property('custom_flags'); - expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); + expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); }); it('should add captured integrations to page view custom flags', async () => { @@ -148,11 +185,10 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); expect(testEvent.data).to.have.property('custom_flags'); - expectCapturedGoogleFacebookFlags( + expectStubbedIntegrationCaptureFlags( testEvent.data.custom_flags, `fb.1.${initialTimestamp}.1234`, ); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => { @@ -170,33 +206,13 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); expect(testEvent.data).to.have.property('custom_flags'); - expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); + expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); }); it('should add captured integrations to commerce event custom flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 - }; - - const customAttributes = {sale: true}; - const customFlags = {foo: 'bar'}; - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); + const testEvent = logCommercePurchaseAndGetEvent({ foo: 'bar' }); const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; @@ -204,60 +220,29 @@ describe('Integration Capture', () => { expect(testEvent.data).to.have.property('custom_flags'); expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expectCapturedGoogleFacebookFlags( + expectStubbedIntegrationCaptureFlags( testEvent.data.custom_flags, `fb.1.${initialTimestamp}.1234`, ); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); }); it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { await waitForCondition(hasIdentifyReturned); - const product1 = mParticle.eCommerce.createProduct('iphone', 'iphoneSKU', 999, 1); - const product2 = mParticle.eCommerce.createProduct('galaxy', 'galaxySKU', 799, 1); - - const transactionAttributes = { - Id: 'foo-transaction-id', - Revenue: 430.00, - Tax: 30 - }; - - const customAttributes = {sale: true}; - const customFlags = { - 'Facebook.ClickId': 'passed-in' - }; - - mParticle.eCommerce.logProductAction( - mParticle.ProductActionType.Purchase, - [product1, product2], - customAttributes, - customFlags, - transactionAttributes); - - - const testEvent = findEventFromRequest(fetchMock.calls(), 'purchase'); + const testEvent = logCommercePurchaseAndGetEvent({ + 'Facebook.ClickId': 'passed-in', + }); expect(testEvent.data.product_action).to.have.property('action', 'purchase'); expect(testEvent.data).to.have.property('custom_flags'); - expectCapturedGoogleFacebookFlags(testEvent.data.custom_flags, 'passed-in'); - expectCapturedSnapchatAndPinterestFlags(testEvent.data.custom_flags); + expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); }); it('should add captured integrations to batch as partner identities', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - - window.mParticle.upload(); - - expect(fetchMock.calls().length).to.greaterThan(1); - - const lastCall = fetchMock.lastCall(); - const batch = JSON.parse(lastCall[1].body as string); + const batch = logThreeEventsUploadAndParseBatch(); expect(batch).to.have.property('partner_identities'); expect(batch.partner_identities).to.deep.equal({ @@ -269,16 +254,7 @@ describe('Integration Capture', () => { it('should add captured integrations to batch as integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - - window.mParticle.upload(); - - expect(fetchMock.calls().length).to.greaterThan(1); - - const lastCall = fetchMock.lastCall(); - const batch = JSON.parse(lastCall[1].body as string); + const batch = logThreeEventsUploadAndParseBatch(); expect(batch).to.have.property('integration_attributes'); expect(batch.integration_attributes['1277']).to.deep.equal({ @@ -291,16 +267,7 @@ describe('Integration Capture', () => { window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - - window.mParticle.upload(); - - expect(fetchMock.calls().length).to.greaterThan(1); - - const lastCall = fetchMock.lastCall(); - const batch = JSON.parse(lastCall[1].body as string); + const batch = logThreeEventsUploadAndParseBatch(); expect(batch).to.have.property('integration_attributes'); expect(batch.integration_attributes).to.have.property('1277'); @@ -320,16 +287,7 @@ describe('Integration Capture', () => { window.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - - window.mParticle.upload(); - - expect(fetchMock.calls().length).to.greaterThan(1); - - const lastCall = fetchMock.lastCall(); - const batch = JSON.parse(lastCall[1].body as string); + const batch = logThreeEventsUploadAndParseBatch(); expect(batch).to.have.property('integration_attributes'); expect(batch.integration_attributes['1277']).to.deep.equal({ From 67e887a4b743e435d1b5d4cd3e69aec04768d2b6 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:31:09 -0700 Subject: [PATCH 14/24] test: data-driven integration capture cases for Sonar duplication Replace duplicated event/pageview and commerce it() bodies with CAPTURE_CUSTOM_FLAG_CASES and COMMERCE_CAPTURE_CASES tables. --- test/src/tests-integration-capture.ts | 239 ++++++++++++++------------ 1 file changed, 132 insertions(+), 107 deletions(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index 9d27ed8ec..55cf46de5 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -83,6 +83,57 @@ function logThreeEventsUploadAndParseBatch(): Record { return JSON.parse(lastCall[1].body as string) as Record; } +type CaptureCustomFlagCase = { + title: string; + kind: 'event' | 'pageView'; + usePassedInFacebook: boolean; +}; + +const CAPTURE_CUSTOM_FLAG_CASES: CaptureCustomFlagCase[] = [ + { + title: 'should add captured integrations to event custom flags', + kind: 'event', + usePassedInFacebook: false, + }, + { + title: 'should add captured integrations to event custom flags, prioritizing passed in custom flags', + kind: 'event', + usePassedInFacebook: true, + }, + { + title: 'should add captured integrations to page view custom flags', + kind: 'pageView', + usePassedInFacebook: false, + }, + { + title: 'should add captured integrations to page view custom flags, prioritizing passed in custom flags', + kind: 'pageView', + usePassedInFacebook: true, + }, +]; + +type CommerceCaptureCase = { + title: string; + customFlags: Record; + expectFooBar: boolean; + usePassedInFacebook: boolean; +}; + +const COMMERCE_CAPTURE_CASES: CommerceCaptureCase[] = [ + { + title: 'should add captured integrations to commerce event custom flags', + customFlags: { foo: 'bar' }, + expectFooBar: true, + usePassedInFacebook: false, + }, + { + title: 'should add captured integrations to commerce event custom flags, prioritizing passed in flags', + customFlags: { 'Facebook.ClickId': 'passed-in' }, + expectFooBar: false, + usePassedInFacebook: true, + }, +]; + describe('Integration Capture', () => { beforeEach(async function() { mParticle._resetForTests(MPConfig); @@ -129,116 +180,90 @@ describe('Integration Capture', () => { deleteAllCookies(); }); - it('should add captured integrations to event custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - mParticle.logEvent( - 'Test Event', - mParticle.EventType.Navigation, - { mykey: 'myvalue' } - ); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - - expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('event_name', 'Test Event'); - expect(testEvent.data).to.have.property('custom_flags'); - - expectStubbedIntegrationCaptureFlags( - testEvent.data.custom_flags, - `fb.1.${initialTimestamp}.1234`, - ); - }); - - it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - window.mParticle.logEvent( - 'Test Event', - mParticle.EventType.Navigation, - { mykey: 'myvalue' }, - { 'Facebook.ClickId': 'passed-in' }, - ); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Event'); - - expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('event_name', 'Test Event'); - expect(testEvent.data).to.have.property('custom_flags'); - - expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); - }); - - it('should add captured integrations to page view custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - - window.mParticle.logPageView( - 'Test Page View', - {'foo-attr': 'bar-attr'} - ); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Page View'); - - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - - expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); - expect(testEvent.data).to.have.property('custom_flags'); - - expectStubbedIntegrationCaptureFlags( - testEvent.data.custom_flags, - `fb.1.${initialTimestamp}.1234`, - ); - }); - - it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - - window.mParticle.logPageView( - 'Test Page View', - {'foo-attr': 'bar-attr'}, - {'Facebook.ClickId': 'passed-in'}, - ); - - const testEvent = findEventFromRequest(fetchMock.calls(), 'Test Page View'); - - expect(testEvent).to.have.property('data'); - expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); - expect(testEvent.data).to.have.property('custom_flags'); - - expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); - }); - - it('should add captured integrations to commerce event custom flags', async () => { - await waitForCondition(hasIdentifyReturned); - - const testEvent = logCommercePurchaseAndGetEvent({ foo: 'bar' }); - - const initialTimestamp = window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; - - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); - expect(testEvent.data).to.have.property('custom_flags'); - - expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal('bar'); - expectStubbedIntegrationCaptureFlags( - testEvent.data.custom_flags, - `fb.1.${initialTimestamp}.1234`, - ); - }); - - it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => { - await waitForCondition(hasIdentifyReturned); - - const testEvent = logCommercePurchaseAndGetEvent({ - 'Facebook.ClickId': 'passed-in', + CAPTURE_CUSTOM_FLAG_CASES.forEach(({ title, kind, usePassedInFacebook }) => { + it(title, async () => { + await waitForCondition(hasIdentifyReturned); + + if (kind === 'event') { + if (usePassedInFacebook) { + mParticle.logEvent( + 'Test Event', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + { 'Facebook.ClickId': 'passed-in' }, + ); + } else { + mParticle.logEvent( + 'Test Event', + mParticle.EventType.Navigation, + { mykey: 'myvalue' }, + ); + } + } else if (usePassedInFacebook) { + mParticle.logPageView( + 'Test Page View', + { 'foo-attr': 'bar-attr' }, + { 'Facebook.ClickId': 'passed-in' }, + ); + } else { + mParticle.logPageView('Test Page View', { 'foo-attr': 'bar-attr' }); + } + + const eventName = kind === 'event' ? 'Test Event' : 'Test Page View'; + const testEvent = findEventFromRequest(fetchMock.calls(), eventName); + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + + expect(testEvent).to.have.property('data'); + if (kind === 'event') { + expect(testEvent.data).to.have.property('event_name', 'Test Event'); + } else { + expect(testEvent.data).to.have.property('screen_name', 'Test Page View'); + } + expect(testEvent.data).to.have.property('custom_flags'); + + const facebookClickId = usePassedInFacebook + ? 'passed-in' + : `fb.1.${initialTimestamp}.1234`; + expectStubbedIntegrationCaptureFlags( + testEvent.data.custom_flags, + facebookClickId, + ); }); - - expect(testEvent.data.product_action).to.have.property('action', 'purchase'); - expect(testEvent.data).to.have.property('custom_flags'); - - expectStubbedIntegrationCaptureFlags(testEvent.data.custom_flags, 'passed-in'); }); + COMMERCE_CAPTURE_CASES.forEach( + ({ title, customFlags, expectFooBar, usePassedInFacebook }) => { + it(title, async () => { + await waitForCondition(hasIdentifyReturned); + + const testEvent = logCommercePurchaseAndGetEvent(customFlags); + const initialTimestamp = + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + + expect(testEvent.data.product_action).to.have.property( + 'action', + 'purchase', + ); + expect(testEvent.data).to.have.property('custom_flags'); + + if (expectFooBar) { + expect(testEvent.data.custom_flags['foo'], 'Custom Flag').to.equal( + 'bar', + ); + } + + const facebookClickId = usePassedInFacebook + ? 'passed-in' + : `fb.1.${initialTimestamp}.1234`; + expectStubbedIntegrationCaptureFlags( + testEvent.data.custom_flags, + facebookClickId, + ); + }); + }, + ); + it('should add captured integrations to batch as partner identities', async () => { await waitForCondition(hasIdentityCallInflightReturned); From 4cc9fa808d4a7eaae0eb233a6d5480fa1cc2a3a9 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:34:46 -0700 Subject: [PATCH 15/24] fix(test): repair Pinterest epik/_epik Jest test and #getClickIdsAsCustomFlags block - Fix indentation and close describe before partner identities suite - Use stable assertions (toBeDefined + includes) per review --- test/jest/integration-capture.spec.ts | 38 +++++++++++++-------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 979c30a8f..07477a80c 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -830,26 +830,24 @@ describe('Integration Capture', () => { }); it('should map both epik and _epik to Pinterest.click_id', () => { - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.clickIds = { - epik: 'pinterest_epik', - _epik: 'pinterest_underscore_epik', - }; - - const customFlags = integrationCapture.getClickIdsAsCustomFlags(); - - // Both map to the same key (support either common key name) - const pinterestKey = Object.keys(customFlags).find( - (k) => k === 'Pinterest.click_id' || k === 'pinterest_click_id' - ); - expect(pinterestKey).toBeDefined(); - expect(customFlags).toHaveProperty(pinterestKey); - - const value = customFlags[pinterestKey]; - expect(value).toBeDefined(); - expect(['pinterest_epik', 'pinterest_underscore_epik']).toContain(value); -}); - + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.clickIds = { + epik: 'pinterest_epik', + _epik: 'pinterest_underscore_epik', + }; + + const customFlags = integrationCapture.getClickIdsAsCustomFlags(); + + // Both map to the same custom flag key; value is whichever is applied last + expect(customFlags['Pinterest.click_id']).toBeDefined(); + expect( + ['pinterest_epik', 'pinterest_underscore_epik'].includes( + customFlags['Pinterest.click_id'], + ), + ).toEqual(true); + }); + }); + describe('#getClickIdsAsPartnerIdentites', () => { it('should return empty object if clickIds is empty or undefined', () => { const integrationCapture = new IntegrationCapture('all'); From 53288fdabe46bdcf86b63bb820b53a320de0126e Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:37:11 -0700 Subject: [PATCH 16/24] fix(test): use globalThis instead of window for Sonar Sonar rule javascript:S7764 prefers globalThis over window in tests; behavior unchanged under jsdom. --- test/jest/integration-capture.spec.ts | 240 +++++++++++++------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 07477a80c..787cf2146 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -67,34 +67,34 @@ describe('Integration Capture', () => { }); describe('capture V2 modes gating in helpers', () => { - const originalLocation = window.location as any; + const originalLocation = globalThis.location as any; beforeEach(() => { - delete (window as any).location; - (window as any).location = { href: 'https://www.example.com/', search: '' } as any; + delete (globalThis as any).location; + (globalThis as any).location = { href: 'https://www.example.com/', search: '' } as any; deleteAllCookies(); - window.localStorage.clear(); + globalThis.localStorage.clear(); jest.restoreAllMocks(); }); afterEach(() => { - window.location = originalLocation; + globalThis.location = originalLocation; deleteAllCookies(); - window.localStorage.clear(); + globalThis.localStorage.clear(); }); it('should return only Rokt keys from helpers when captureMode is roktonly (lowercase)', () => { // Query params const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; // Cookies document.cookie = '_fbp=54321'; document.cookie = 'RoktTransactionId=xyz'; // Local storage - window.localStorage.setItem('RoktTransactionId', 'ls-rok'); + globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); const integrationCapture = new IntegrationCapture('roktonly'); @@ -111,8 +111,8 @@ describe('Integration Capture', () => { jest.spyOn(Date, 'now').mockImplementation(() => 42); // Query params const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; // Cookies document.cookie = '_fbp=54321'; @@ -120,7 +120,7 @@ describe('Integration Capture', () => { document.cookie = 'RoktTransactionId=xyz'; // Local storage - window.localStorage.setItem('RoktTransactionId', 'ls-rok'); + globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); const integrationCapture = new IntegrationCapture('all'); @@ -138,8 +138,8 @@ describe('Integration Capture', () => { jest.spyOn(Date, 'now').mockImplementation(() => 42); // Query params const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; // Cookies document.cookie = '_fbp=54321'; @@ -147,7 +147,7 @@ describe('Integration Capture', () => { document.cookie = 'RoktTransactionId=xyz'; // Local storage - window.localStorage.setItem('RoktTransactionId', 'ls-rok'); + globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); const integrationCapture = new IntegrationCapture('none'); @@ -162,11 +162,11 @@ describe('Integration Capture', () => { }); describe('#capture', () => { - const originalLocation = window.location; + const originalLocation = globalThis.location; beforeEach(() => { - delete (window as any).location; - (window as any).location = { + delete (globalThis as any).location; + (globalThis as any).location = { href: '', search: '', assign: jest.fn(), @@ -178,8 +178,8 @@ describe('Integration Capture', () => { }); afterEach(() => { - window.location = originalLocation; - window.localStorage.clear(); + globalThis.location = originalLocation; + globalThis.localStorage.clear(); jest.restoreAllMocks(); }); @@ -208,13 +208,13 @@ describe('Integration Capture', () => { const url = new URL(`https://www.example.com/?${queryParams}`); - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = '_fbp=54321'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = '_fbp=54321'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -235,8 +235,8 @@ describe('Integration Capture', () => { it('should capture Google specific click ids', () => { const url = new URL('https://www.example.com/?gclid=54321&gbraid=67890&wbraid=09876'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -253,8 +253,8 @@ describe('Integration Capture', () => { it('should capture Snapchat specific click ids', () => { const url = new URL('https://www.example.com/?ScCid=1234'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -267,8 +267,8 @@ describe('Integration Capture', () => { it('should capture Snapchat specific click ids without being case sensitive', () => { const url = new URL('https://www.example.com/?sccid=1234'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -281,12 +281,12 @@ describe('Integration Capture', () => { it('should capture _scid from cookies', () => { const url = new URL('https://www.example.com/'); - window.document.cookie = '_scid=cookie1-from-cookie'; - window.document.cookie = '_cookie1=4567'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_scid=cookie1-from-cookie'; + globalThis.document.cookie = '_cookie1=4567'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -299,11 +299,11 @@ describe('Integration Capture', () => { it('should capture both ScCid from query params and _scid from cookies', () => { const url = new URL('https://www.example.com/?ScCid=4567'); - window.document.cookie = '_scid=cookie1-from-cookie'; - window.document.cookie = '_cookie1=334455'; + globalThis.document.cookie = '_scid=cookie1-from-cookie'; + globalThis.document.cookie = '_cookie1=334455'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -319,8 +319,8 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from query params (_epik)', () => { const url = new URL('https://www.example.com/?_epik=1234'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -333,8 +333,8 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from query params (epik)', () => { const url = new URL('https://www.example.com/?epik=5678'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -347,9 +347,9 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from cookies (_epik)', () => { const url = new URL('https://www.example.com/'); - window.document.cookie = '_epik=pinterest_cookie_value'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.document.cookie = '_epik=pinterest_cookie_value'; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -362,9 +362,9 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from cookies (epik)', () => { const url = new URL('https://www.example.com/'); - window.document.cookie = 'epik=pinterest_cookie_value_epik'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.document.cookie = 'epik=pinterest_cookie_value_epik'; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -377,8 +377,8 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from localStorage (_epik)', () => { const url = new URL('https://www.example.com/'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('_epik', 'pinterest_localstorage_value'); @@ -393,8 +393,8 @@ describe('Integration Capture', () => { it('should capture Pinterest specific click ids from localStorage (epik)', () => { const url = new URL('https://www.example.com/'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('epik', 'pinterest_localstorage_value_epik'); @@ -415,12 +415,12 @@ describe('Integration Capture', () => { 'https://www.example.com/?fbclid=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890' ); - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -434,14 +434,14 @@ describe('Integration Capture', () => { it('should pass the _fbc value unaltered', () => { const url = new URL('https://www.example.com/?foo=bar'); - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = '_fbc=fb.1.1554763741205.AbCdEfGhIjKlMnOpQrStUvWxYz1234567890'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -454,13 +454,13 @@ describe('Integration Capture', () => { it('should pass the _fbp value unaltered', () => { const url = new URL('https://www.example.com/?foo=bar'); - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = '_fbp=54321'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = '_fbp=54321'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -475,13 +475,13 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?fbclid=12345&'); - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = '_fbc=fb.1.23.654321'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = '_fbc=fb.1.23.654321'; + globalThis.document.cookie = 'baz=qux'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -496,8 +496,8 @@ describe('Integration Capture', () => { it('should capture rtid via url param', () => { const url = new URL('https://www.example.com/?rtid=54321'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -510,8 +510,8 @@ describe('Integration Capture', () => { it('should capture rclid via url param', () => { const url = new URL('https://www.example.com/?rclid=7183717'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -522,12 +522,12 @@ describe('Integration Capture', () => { }); it('should capture RoktTransactionId via cookies', () => { - window.document.cookie = 'RoktTransactionId=12345'; + globalThis.document.cookie = 'RoktTransactionId=12345'; const url = new URL('https://www.example.com/'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -542,8 +542,8 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('RoktTransactionId', '54321'); @@ -560,10 +560,10 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?rtid=54321'); - window.document.cookie = 'RoktTransactionId=12345'; + globalThis.document.cookie = 'RoktTransactionId=12345'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -578,10 +578,10 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?rclid=7183717'); - window.document.cookie = 'RoktTransactionId=12345'; + globalThis.document.cookie = 'RoktTransactionId=12345'; - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -596,8 +596,8 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?rtid=54321'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('RoktTransactionId', '12345'); @@ -614,8 +614,8 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?rclid=7183717'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('RoktTransactionId', '12345'); @@ -632,11 +632,11 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/'); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; localStorage.setItem('RoktTransactionId', '12345'); - window.document.cookie = 'RoktTransactionId=67890'; + globalThis.document.cookie = 'RoktTransactionId=67890'; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -650,11 +650,11 @@ describe('Integration Capture', () => { }); describe('#captureQueryParams', () => { - const originalLocation = window.location; + const originalLocation = globalThis.location; beforeEach(() => { - delete (window as any).location; - (window as any).location = { + delete (globalThis as any).location; + (globalThis as any).location = { href: '', search: '', assign: jest.fn(), @@ -664,7 +664,7 @@ describe('Integration Capture', () => { }); afterEach(() => { - window.location = originalLocation; + globalThis.location = originalLocation; jest.restoreAllMocks(); }); @@ -675,8 +675,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?ttclid=12345&fbclid=67890&gclid=54321&rclid=7183717&rtid=54321' ); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureQueryParams(); @@ -695,8 +695,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?invalidid=12345&foo=bar' ); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureQueryParams(); @@ -708,8 +708,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?fbclid=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890' ); - window.location.href = url.href; - window.location.search = url.search; + globalThis.location.href = url.href; + globalThis.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -730,10 +730,10 @@ describe('Integration Capture', () => { }); it('should capture specific cookies into clickIds object', () => { - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = '_fbp=54321'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = '_fbp=54321'; + globalThis.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); @@ -744,9 +744,9 @@ describe('Integration Capture', () => { }); it('should capture _scid from cookies', () => { - window.document.cookie = '_cookie1=4567'; - window.document.cookie = '_scid=cookie1-from-cookie'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=4567'; + globalThis.document.cookie = '_scid=cookie1-from-cookie'; + globalThis.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); @@ -757,9 +757,9 @@ describe('Integration Capture', () => { }); it('should NOT capture cookies if they are not mapped', () => { - window.document.cookie = '_cookie1=1234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_cookie1=1234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); From ad190b74b83b9ab8eb2790847a8a9fd8b46d4cea Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:39:29 -0700 Subject: [PATCH 17/24] fix(test): drop redundant .0 from commerce Revenue literal Satisfies Sonar no-zero-fraction rule; value unchanged. --- test/src/tests-integration-capture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index 55cf46de5..f61429baa 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -52,7 +52,7 @@ function expectStubbedIntegrationCaptureFlags( expectCapturedSnapchatAndPinterestFlags(customFlags); } -const COMMERCE_TRANSACTION_ATTRS = { Id: 'foo-transaction-id', Revenue: 430.0, Tax: 30 }; +const COMMERCE_TRANSACTION_ATTRS = { Id: 'foo-transaction-id', Revenue: 430, Tax: 30 }; const COMMERCE_CUSTOM_ATTRS = { sale: true }; function createCommercePurchaseProducts() { From 63f81ac2fbef829b9c24a31c8d8aa5ce71b50009 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:42:12 -0700 Subject: [PATCH 18/24] fix(test): use globalThis in tests-integration-capture for Sonar --- test/src/tests-integration-capture.ts | 42 +++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index f61429baa..b4dad64f1 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -21,7 +21,7 @@ declare global { } } -const mParticle = window.mParticle as IMParticleInstanceManager; +const mParticle = globalThis.mParticle as IMParticleInstanceManager; /** Expected integration-capture custom flags from stubbed query params + _scid cookie */ function expectCapturedSnapchatAndPinterestFlags( @@ -74,10 +74,10 @@ function logCommercePurchaseAndGetEvent(customFlags: Record) { } function logThreeEventsUploadAndParseBatch(): Record { - window.mParticle.logEvent('Test Event 1'); - window.mParticle.logEvent('Test Event 2'); - window.mParticle.logEvent('Test Event 3'); - window.mParticle.upload(); + globalThis.mParticle.logEvent('Test Event 1'); + globalThis.mParticle.logEvent('Test Event 2'); + globalThis.mParticle.logEvent('Test Event 3'); + globalThis.mParticle.upload(); expect(fetchMock.calls().length).to.greaterThan(1); const lastCall = fetchMock.lastCall(); return JSON.parse(lastCall[1].body as string) as Record; @@ -145,22 +145,22 @@ describe('Integration Capture', () => { mpid: testMPID, is_logged_in: false }); - window.mParticle.config.flags = { + globalThis.mParticle.config.flags = { captureIntegrationSpecificIds: 'True', captureIntegrationSpecificIdsV2: 'all' }; - window.document.cookie = '_cookie1=234'; - window.document.cookie = '_cookie2=39895811.9165333198'; - window.document.cookie = 'foo=bar'; - window.document.cookie = '_fbp=54321'; - window.document.cookie = 'baz=qux'; - window.document.cookie = '_ttp=45670808'; - window.document.cookie = '_scid=cookie1-value'; - mParticle.init(apiKey, window.mParticle.config); + globalThis.document.cookie = '_cookie1=234'; + globalThis.document.cookie = '_cookie2=39895811.9165333198'; + globalThis.document.cookie = 'foo=bar'; + globalThis.document.cookie = '_fbp=54321'; + globalThis.document.cookie = 'baz=qux'; + globalThis.document.cookie = '_ttp=45670808'; + globalThis.document.cookie = '_scid=cookie1-value'; + mParticle.init(apiKey, globalThis.mParticle.config); await waitForCondition(hasIdentifyReturned); - const integrationCapture = window.mParticle.getInstance()._IntegrationCapture; - // Mock the query params capture function because we cannot mock window.location.href + const integrationCapture = globalThis.mParticle.getInstance()._IntegrationCapture; + // Mock the query params capture function because we cannot mock globalThis.location.href sinon.stub(integrationCapture, 'getQueryParams').returns({ fbclid: '1234', gclid: '234', @@ -212,7 +212,7 @@ describe('Integration Capture', () => { const eventName = kind === 'event' ? 'Test Event' : 'Test Page View'; const testEvent = findEventFromRequest(fetchMock.calls(), eventName); const initialTimestamp = - window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + globalThis.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent).to.have.property('data'); if (kind === 'event') { @@ -239,7 +239,7 @@ describe('Integration Capture', () => { const testEvent = logCommercePurchaseAndGetEvent(customFlags); const initialTimestamp = - window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + globalThis.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent.data.product_action).to.have.property( 'action', @@ -290,7 +290,7 @@ describe('Integration Capture', () => { it('should add captured integrations to batch as integration attributes without colliding with set integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + globalThis.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); const batch = logThreeEventsUploadAndParseBatch(); @@ -309,8 +309,8 @@ describe('Integration Capture', () => { it('should add captured integrations to batch as integration attributes, prioritizing passed in integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - window.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); - window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + globalThis.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); + globalThis.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); const batch = logThreeEventsUploadAndParseBatch(); From 84979c448d5146f73bf06758b5e31780f74e09a9 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:45:31 -0700 Subject: [PATCH 19/24] fix(integrationCapture): close _epik mapping before _scid A missing brace nested _scid under _epik and broke integrationMappingExternal parsing. Restore _scid as a top-level key next to Pinterest entries. --- src/integrationCapture.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index 43a3cd44b..c8b3bf050 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -131,6 +131,8 @@ const integrationMappingExternal: IntegrationIdMapping = { _epik: { mappedKey: 'Pinterest.click_id', output: IntegrationOutputs.CUSTOM_FLAGS, + }, + // Snapchat // https://developers.snap.com/api/marketing-api/Conversions-API/UsingTheAPI#sending-click-id _scid: { From ef32e83cb4a5f9b873fb9c93d1dbb527192ed6ea Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:51:37 -0700 Subject: [PATCH 20/24] test(integration-capture): clarify epik/_epik custom flag collision test Assert both Pinterest source keys are registered in filtered mappings, then that Pinterest.click_id is one of the input values (same key, last-write wins). --- test/jest/integration-capture.spec.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 787cf2146..47e2e2262 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -831,20 +831,22 @@ describe('Integration Capture', () => { it('should map both epik and _epik to Pinterest.click_id', () => { const integrationCapture = new IntegrationCapture('all'); + expect(integrationCapture.filteredCustomFlagMappings.epik).toBeDefined(); + expect(integrationCapture.filteredCustomFlagMappings._epik).toBeDefined(); + integrationCapture.clickIds = { epik: 'pinterest_epik', _epik: 'pinterest_underscore_epik', }; const customFlags = integrationCapture.getClickIdsAsCustomFlags(); + const pinterestClickId = customFlags['Pinterest.click_id']; - // Both map to the same custom flag key; value is whichever is applied last - expect(customFlags['Pinterest.click_id']).toBeDefined(); - expect( - ['pinterest_epik', 'pinterest_underscore_epik'].includes( - customFlags['Pinterest.click_id'], - ), - ).toEqual(true); + // Same mappedKey: last key wins depends on for-in order; value must be one of the inputs. + expect(pinterestClickId).toBeDefined(); + expect(['pinterest_epik', 'pinterest_underscore_epik']).toContain( + pinterestClickId, + ); }); }); From 63d6c7541a00486ad51755d7bf738128c8bed887 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 11:55:13 -0700 Subject: [PATCH 21/24] fix(integrationCapture): dedupe Pinterest epik/_epik by source priority epik and _epik map to the same custom flag. Prefer query params over localStorage and cookies, then localStorage over cookies, mirroring Facebook fbclid/_fbc and Rokt-style precedence. Add Jest coverage for each tier. --- src/integrationCapture.ts | 20 +++++++++++ test/jest/integration-capture.spec.ts | 49 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/integrationCapture.ts b/src/integrationCapture.ts index c8b3bf050..d0e455646 100644 --- a/src/integrationCapture.ts +++ b/src/integrationCapture.ts @@ -195,6 +195,26 @@ export default class IntegrationCapture { delete cookies['_fbc']; } + // Pinterest Rules + // epik and _epik both map to Pinterest.click_id. Prefer query params over + // localStorage and cookies (same rationale as Facebook fbclid vs _fbc). + // https://help.pinterest.com/en/business/article/pinterest-tag-parameters-and-cookies + const hasPinterestQuery = + !isEmpty(queryParams['epik']) || !isEmpty(queryParams['_epik']); + if (hasPinterestQuery) { + delete cookies['epik']; + delete cookies['_epik']; + delete localStorage['epik']; + delete localStorage['_epik']; + } else { + const hasPinterestLocalStorage = + !isEmpty(localStorage['epik']) || !isEmpty(localStorage['_epik']); + if (hasPinterestLocalStorage) { + delete cookies['epik']; + delete cookies['_epik']; + } + } + // ROKT Rules // If both rtid or rclid and RoktTransactionId are present, prioritize rtid/rclid // If RoktTransactionId is present in both cookies and localStorage, diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 47e2e2262..8a41e2e85 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -405,6 +405,55 @@ describe('Integration Capture', () => { epik: 'pinterest_localstorage_value_epik', }); }); + + it('should prefer Pinterest query param over cookie when both are present', () => { + const url = new URL('https://www.example.com/?epik=from_query'); + + globalThis.document.cookie = '_epik=from_cookie'; + globalThis.document.cookie = 'epik=from_cookie_epik'; + globalThis.location.href = url.href; + globalThis.location.search = url.search; + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + epik: 'from_query', + }); + }); + + it('should prefer Pinterest query param over localStorage when both are present', () => { + const url = new URL('https://www.example.com/?_epik=from_query'); + + globalThis.location.href = url.href; + globalThis.location.search = url.search; + localStorage.setItem('epik', 'from_ls'); + localStorage.setItem('_epik', 'from_ls_underscore'); + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + _epik: 'from_query', + }); + }); + + it('should prefer Pinterest localStorage over cookie when both are present', () => { + const url = new URL('https://www.example.com/'); + + globalThis.document.cookie = 'epik=from_cookie'; + globalThis.document.cookie = '_epik=from_cookie_us'; + globalThis.location.href = url.href; + globalThis.location.search = url.search; + localStorage.setItem('_epik', 'from_ls'); + + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + + expect(integrationCapture.clickIds).toEqual({ + _epik: 'from_ls', + }); + }); }); describe('Facebook Click Ids', () => { From 48c78fe3c80ed85e845b2a5f8cd1439f6712666d Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 12:01:51 -0700 Subject: [PATCH 22/24] test(integration-capture): dedupe Jest setup for Sonar duplication Add clickIdsAfterFullCaptureAllMode helper; drive Pinterest, Snapchat, and Rokt #capture cases from tables; consolidate capture V2 mode gating tests. --- test/jest/integration-capture.spec.ts | 760 +++++++++++--------------- 1 file changed, 331 insertions(+), 429 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 8a41e2e85..7cd7bd33d 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -3,6 +3,35 @@ import IntegrationCapture, { } from '../../src/integrationCapture'; import { deleteAllCookies } from './utils'; +type FullCaptureSetup = { + url: string; + cookies?: string[]; + localStorage?: Record; + mockNow?: number; +}; + +/** Sets location from URL, optional cookies/localStorage, runs IntegrationCapture('all').capture(). */ +function clickIdsAfterFullCaptureAllMode(setup: FullCaptureSetup): Record { + const { url, cookies, localStorage: ls, mockNow } = setup; + if (mockNow !== undefined) { + jest.spyOn(Date, 'now').mockImplementation(() => mockNow); + } + const urlObj = new URL(url); + cookies?.forEach((c) => { + globalThis.document.cookie = c; + }); + if (ls) { + for (const [key, val] of Object.entries(ls)) { + globalThis.localStorage.setItem(key, val); + } + } + globalThis.location.href = urlObj.href; + globalThis.location.search = urlObj.search; + const integrationCapture = new IntegrationCapture('all'); + integrationCapture.capture(); + return (integrationCapture.clickIds ?? {}) as Record; +} + describe('Integration Capture', () => { describe('constructor', () => { it('should initialize with clickIds as undefined', () => { @@ -83,82 +112,100 @@ describe('Integration Capture', () => { globalThis.localStorage.clear(); }); - it('should return only Rokt keys from helpers when captureMode is roktonly (lowercase)', () => { - // Query params - const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1'); - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - // Cookies - document.cookie = '_fbp=54321'; - document.cookie = 'RoktTransactionId=xyz'; - - // Local storage - globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); - - const integrationCapture = new IntegrationCapture('roktonly'); - - const clickIds = integrationCapture.captureQueryParams(); - const clickIdCookies = integrationCapture.captureCookies(); - const clickIdLocalStorage = integrationCapture.captureLocalStorage(); - - expect(clickIds).toEqual({ rtid: 'rt1', rclid: 'rc1' }); - expect(clickIdCookies).toEqual({ RoktTransactionId: 'xyz' }); - expect(clickIdLocalStorage).toEqual({ RoktTransactionId: 'ls-rok' }); - }); - - it('should return all mapped keys from helpers when captureMode is all (lowercase)', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - // Query params - const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1'); - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - // Cookies - document.cookie = '_fbp=54321'; - document.cookie = '_fbc=fb.1.1554763741205.abcdef'; - document.cookie = 'RoktTransactionId=xyz'; - - // Local storage - globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); - - const integrationCapture = new IntegrationCapture('all'); - - const clickIds = integrationCapture.captureQueryParams(); - const clickIdCookies = integrationCapture.captureCookies(); - const clickIdLocalStorage = integrationCapture.captureLocalStorage(); - - // fbclid is formatted with timestamp/domain index - expect(clickIds).toMatchObject({ fbclid: 'fb.2.42.abc', gclid: 'g1', rtid: 'rt1', rclid: 'rc1', ScCid: 'snap1' }); - expect(clickIdCookies).toMatchObject({ _fbp: '54321', _fbc: 'fb.1.1554763741205.abcdef', RoktTransactionId: 'xyz' }); - expect(clickIdLocalStorage).toEqual({ RoktTransactionId: 'ls-rok' }); - }); - - it('should NOT return mapped keys from helpers when captureMode is none (lowercase)', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - // Query params - const url = new URL('https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1'); - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - // Cookies - document.cookie = '_fbp=54321'; - document.cookie = '_fbc=fb.1.1554763741205.abcdef'; - document.cookie = 'RoktTransactionId=xyz'; - - // Local storage - globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); - - const integrationCapture = new IntegrationCapture('none'); - - const clickIds = integrationCapture.captureQueryParams(); - const clickIdCookies = integrationCapture.captureCookies(); - const clickIdLocalStorage = integrationCapture.captureLocalStorage(); - - expect(clickIds).toMatchObject({}); - expect(clickIdCookies).toMatchObject({}); - expect(clickIdLocalStorage).toEqual({}); - }); + const V2_MODE_HELPER_CASES: Array<{ + title: string; + captureMode: 'roktonly' | 'all' | 'none'; + url: string; + cookies: string[]; + mockNow?: number; + expectQuery: Record; + expectCookies: Record; + expectLocalStorage: Record; + }> = [ + { + title: 'should return only Rokt keys from helpers when captureMode is roktonly (lowercase)', + captureMode: 'roktonly', + url: 'https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1', + cookies: ['_fbp=54321', 'RoktTransactionId=xyz'], + expectQuery: { rtid: 'rt1', rclid: 'rc1' }, + expectCookies: { RoktTransactionId: 'xyz' }, + expectLocalStorage: { RoktTransactionId: 'ls-rok' }, + }, + { + title: 'should return all mapped keys from helpers when captureMode is all (lowercase)', + captureMode: 'all', + url: 'https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1', + cookies: [ + '_fbp=54321', + '_fbc=fb.1.1554763741205.abcdef', + 'RoktTransactionId=xyz', + ], + mockNow: 42, + expectQuery: { + fbclid: 'fb.2.42.abc', + gclid: 'g1', + rtid: 'rt1', + rclid: 'rc1', + ScCid: 'snap1', + }, + expectCookies: { + _fbp: '54321', + _fbc: 'fb.1.1554763741205.abcdef', + RoktTransactionId: 'xyz', + }, + expectLocalStorage: { RoktTransactionId: 'ls-rok' }, + }, + { + title: 'should NOT return mapped keys from helpers when captureMode is none (lowercase)', + captureMode: 'none', + url: 'https://www.example.com/?fbclid=abc&gclid=g1&rtid=rt1&rclid=rc1&ScCid=snap1', + cookies: [ + '_fbp=54321', + '_fbc=fb.1.1554763741205.abcdef', + 'RoktTransactionId=xyz', + ], + mockNow: 42, + expectQuery: {}, + expectCookies: {}, + expectLocalStorage: {}, + }, + ]; + + V2_MODE_HELPER_CASES.forEach( + ({ + title, + captureMode, + url, + cookies, + mockNow, + expectQuery, + expectCookies, + expectLocalStorage, + }) => { + it(title, () => { + if (mockNow !== undefined) { + jest.spyOn(Date, 'now').mockImplementation(() => mockNow); + } + const urlObj = new URL(url); + globalThis.location.href = urlObj.href; + globalThis.location.search = urlObj.search; + cookies.forEach((c) => { + document.cookie = c; + }); + globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); + + const integrationCapture = new IntegrationCapture(captureMode); + + const clickIds = integrationCapture.captureQueryParams(); + const clickIdCookies = integrationCapture.captureCookies(); + const clickIdLocalStorage = integrationCapture.captureLocalStorage(); + + expect(clickIds).toMatchObject(expectQuery); + expect(clickIdCookies).toMatchObject(expectCookies); + expect(clickIdLocalStorage).toEqual(expectLocalStorage); + }); + }, + ); }); describe('#capture', () => { @@ -233,15 +280,11 @@ describe('Integration Capture', () => { describe('Google Click Ids', () => { it('should capture Google specific click ids', () => { - const url = new URL('https://www.example.com/?gclid=54321&gbraid=67890&wbraid=09876'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ + expect( + clickIdsAfterFullCaptureAllMode({ + url: 'https://www.example.com/?gclid=54321&gbraid=67890&wbraid=09876', + }), + ).toEqual({ gclid: '54321', gbraid: '67890', wbraid: '09876', @@ -250,208 +293,134 @@ describe('Integration Capture', () => { }); describe('SnapChat Click Ids', () => { - it('should capture Snapchat specific click ids', () => { - const url = new URL('https://www.example.com/?ScCid=1234'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - ScCid: '1234', - }); - }); - - it('should capture Snapchat specific click ids without being case sensitive', () => { - const url = new URL('https://www.example.com/?sccid=1234'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - ScCid: '1234', - }); - }); - - it('should capture _scid from cookies', () => { - const url = new URL('https://www.example.com/'); - - globalThis.document.cookie = '_scid=cookie1-from-cookie'; - globalThis.document.cookie = '_cookie1=4567'; - globalThis.document.cookie = 'baz=qux'; - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - _scid: 'cookie1-from-cookie', - }); - }); - - it('should capture both ScCid from query params and _scid from cookies', () => { - const url = new URL('https://www.example.com/?ScCid=4567'); - - globalThis.document.cookie = '_scid=cookie1-from-cookie'; - globalThis.document.cookie = '_cookie1=334455'; - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); + const SNAPCHAT_FULL_CAPTURE: Array<{ + title: string; + setup: FullCaptureSetup; + expected: Record; + }> = [ + { + title: 'should capture Snapchat specific click ids', + setup: { url: 'https://www.example.com/?ScCid=1234' }, + expected: { ScCid: '1234' }, + }, + { + title: 'should capture Snapchat specific click ids without being case sensitive', + setup: { url: 'https://www.example.com/?sccid=1234' }, + expected: { ScCid: '1234' }, + }, + { + title: 'should capture _scid from cookies', + setup: { + url: 'https://www.example.com/', + cookies: [ + '_scid=cookie1-from-cookie', + '_cookie1=4567', + 'baz=qux', + ], + }, + expected: { _scid: 'cookie1-from-cookie' }, + }, + { + title: 'should capture both ScCid from query params and _scid from cookies', + setup: { + url: 'https://www.example.com/?ScCid=4567', + cookies: ['_scid=cookie1-from-cookie', '_cookie1=334455'], + }, + expected: { + ScCid: '4567', + _scid: 'cookie1-from-cookie', + }, + }, + ]; - expect(integrationCapture.clickIds).toEqual({ - ScCid: '4567', - _scid: 'cookie1-from-cookie', + SNAPCHAT_FULL_CAPTURE.forEach(({ title, setup, expected }) => { + it(title, () => { + expect(clickIdsAfterFullCaptureAllMode(setup)).toEqual(expected); }); }); }); describe('Pinterest Click Ids', () => { - it('should capture Pinterest specific click ids from query params (_epik)', () => { - const url = new URL('https://www.example.com/?_epik=1234'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - _epik: '1234', - }); - }); - - it('should capture Pinterest specific click ids from query params (epik)', () => { - const url = new URL('https://www.example.com/?epik=5678'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - epik: '5678', - }); - }); - - it('should capture Pinterest specific click ids from cookies (_epik)', () => { - const url = new URL('https://www.example.com/'); - - globalThis.document.cookie = '_epik=pinterest_cookie_value'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - _epik: 'pinterest_cookie_value', - }); - }); - - it('should capture Pinterest specific click ids from cookies (epik)', () => { - const url = new URL('https://www.example.com/'); - - globalThis.document.cookie = 'epik=pinterest_cookie_value_epik'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - epik: 'pinterest_cookie_value_epik', - }); - }); - - it('should capture Pinterest specific click ids from localStorage (_epik)', () => { - const url = new URL('https://www.example.com/'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('_epik', 'pinterest_localstorage_value'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - _epik: 'pinterest_localstorage_value', - }); - }); - - it('should capture Pinterest specific click ids from localStorage (epik)', () => { - const url = new URL('https://www.example.com/'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('epik', 'pinterest_localstorage_value_epik'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - epik: 'pinterest_localstorage_value_epik', - }); - }); - - it('should prefer Pinterest query param over cookie when both are present', () => { - const url = new URL('https://www.example.com/?epik=from_query'); - - globalThis.document.cookie = '_epik=from_cookie'; - globalThis.document.cookie = 'epik=from_cookie_epik'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - epik: 'from_query', - }); - }); - - it('should prefer Pinterest query param over localStorage when both are present', () => { - const url = new URL('https://www.example.com/?_epik=from_query'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - localStorage.setItem('epik', 'from_ls'); - localStorage.setItem('_epik', 'from_ls_underscore'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - _epik: 'from_query', - }); - }); - - it('should prefer Pinterest localStorage over cookie when both are present', () => { - const url = new URL('https://www.example.com/'); - - globalThis.document.cookie = 'epik=from_cookie'; - globalThis.document.cookie = '_epik=from_cookie_us'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; - localStorage.setItem('_epik', 'from_ls'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); + const PINTEREST_FULL_CAPTURE: Array<{ + title: string; + setup: FullCaptureSetup; + expected: Record; + }> = [ + { + title: 'should capture Pinterest specific click ids from query params (_epik)', + setup: { url: 'https://www.example.com/?_epik=1234' }, + expected: { _epik: '1234' }, + }, + { + title: 'should capture Pinterest specific click ids from query params (epik)', + setup: { url: 'https://www.example.com/?epik=5678' }, + expected: { epik: '5678' }, + }, + { + title: 'should capture Pinterest specific click ids from cookies (_epik)', + setup: { + url: 'https://www.example.com/', + cookies: ['_epik=pinterest_cookie_value'], + }, + expected: { _epik: 'pinterest_cookie_value' }, + }, + { + title: 'should capture Pinterest specific click ids from cookies (epik)', + setup: { + url: 'https://www.example.com/', + cookies: ['epik=pinterest_cookie_value_epik'], + }, + expected: { epik: 'pinterest_cookie_value_epik' }, + }, + { + title: 'should capture Pinterest specific click ids from localStorage (_epik)', + setup: { + url: 'https://www.example.com/', + localStorage: { _epik: 'pinterest_localstorage_value' }, + }, + expected: { _epik: 'pinterest_localstorage_value' }, + }, + { + title: 'should capture Pinterest specific click ids from localStorage (epik)', + setup: { + url: 'https://www.example.com/', + localStorage: { epik: 'pinterest_localstorage_value_epik' }, + }, + expected: { epik: 'pinterest_localstorage_value_epik' }, + }, + { + title: 'should prefer Pinterest query param over cookie when both are present', + setup: { + url: 'https://www.example.com/?epik=from_query', + cookies: ['_epik=from_cookie', 'epik=from_cookie_epik'], + }, + expected: { epik: 'from_query' }, + }, + { + title: 'should prefer Pinterest query param over localStorage when both are present', + setup: { + url: 'https://www.example.com/?_epik=from_query', + localStorage: { + epik: 'from_ls', + _epik: 'from_ls_underscore', + }, + }, + expected: { _epik: 'from_query' }, + }, + { + title: 'should prefer Pinterest localStorage over cookie when both are present', + setup: { + url: 'https://www.example.com/', + cookies: ['epik=from_cookie', '_epik=from_cookie_us'], + localStorage: { _epik: 'from_ls' }, + }, + expected: { _epik: 'from_ls' }, + }, + ]; - expect(integrationCapture.clickIds).toEqual({ - _epik: 'from_ls', + PINTEREST_FULL_CAPTURE.forEach(({ title, setup, expected }) => { + it(title, () => { + expect(clickIdsAfterFullCaptureAllMode(setup)).toEqual(expected); }); }); }); @@ -542,156 +511,89 @@ describe('Integration Capture', () => { }); describe('Rokt Click Ids', () => { - it('should capture rtid via url param', () => { - const url = new URL('https://www.example.com/?rtid=54321'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rtid: '54321', - }); - }); - - it('should capture rclid via url param', () => { - const url = new URL('https://www.example.com/?rclid=7183717'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rclid: '7183717', - }); - }); - - it('should capture RoktTransactionId via cookies', () => { - globalThis.document.cookie = 'RoktTransactionId=12345'; - - const url = new URL('https://www.example.com/'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - RoktTransactionId: '12345', - }); - }); - - it('should capture RoktTransactionId via local storage', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('RoktTransactionId', '54321'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - RoktTransactionId: '54321', - }); - }); - - it('should prioritize rtid over RoktTransactionId via cookies', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/?rtid=54321'); - - globalThis.document.cookie = 'RoktTransactionId=12345'; - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rtid: '54321', - }); - }); - - it('should prioritize rclid over RoktTransactionId via cookies', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/?rclid=7183717'); - - globalThis.document.cookie = 'RoktTransactionId=12345'; - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rclid: '7183717', - }); - }); - - it('should prioritize rtid over RoktTransactionId via local storage', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/?rtid=54321'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('RoktTransactionId', '12345'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rtid: '54321', - }); - }); - - it('should prioritize rclid over RoktTransactionId via local storage', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/?rclid=7183717'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('RoktTransactionId', '12345'); - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); - - expect(integrationCapture.clickIds).toEqual({ - rclid: '7183717', - }); - }); - - it('should prioritize local storage over cookies', () => { - jest.spyOn(Date, 'now').mockImplementation(() => 42); - - const url = new URL('https://www.example.com/'); - - globalThis.location.href = url.href; - globalThis.location.search = url.search; - - localStorage.setItem('RoktTransactionId', '12345'); - globalThis.document.cookie = 'RoktTransactionId=67890'; - - const integrationCapture = new IntegrationCapture('all'); - integrationCapture.capture(); + const ROKT_FULL_CAPTURE: Array<{ + title: string; + setup: FullCaptureSetup; + expected: Record; + }> = [ + { + title: 'should capture rtid via url param', + setup: { url: 'https://www.example.com/?rtid=54321' }, + expected: { rtid: '54321' }, + }, + { + title: 'should capture rclid via url param', + setup: { url: 'https://www.example.com/?rclid=7183717' }, + expected: { rclid: '7183717' }, + }, + { + title: 'should capture RoktTransactionId via cookies', + setup: { + url: 'https://www.example.com/', + cookies: ['RoktTransactionId=12345'], + }, + expected: { RoktTransactionId: '12345' }, + }, + { + title: 'should capture RoktTransactionId via local storage', + setup: { + url: 'https://www.example.com/', + localStorage: { RoktTransactionId: '54321' }, + mockNow: 42, + }, + expected: { RoktTransactionId: '54321' }, + }, + { + title: 'should prioritize rtid over RoktTransactionId via cookies', + setup: { + url: 'https://www.example.com/?rtid=54321', + cookies: ['RoktTransactionId=12345'], + mockNow: 42, + }, + expected: { rtid: '54321' }, + }, + { + title: 'should prioritize rclid over RoktTransactionId via cookies', + setup: { + url: 'https://www.example.com/?rclid=7183717', + cookies: ['RoktTransactionId=12345'], + mockNow: 42, + }, + expected: { rclid: '7183717' }, + }, + { + title: 'should prioritize rtid over RoktTransactionId via local storage', + setup: { + url: 'https://www.example.com/?rtid=54321', + localStorage: { RoktTransactionId: '12345' }, + mockNow: 42, + }, + expected: { rtid: '54321' }, + }, + { + title: 'should prioritize rclid over RoktTransactionId via local storage', + setup: { + url: 'https://www.example.com/?rclid=7183717', + localStorage: { RoktTransactionId: '12345' }, + mockNow: 42, + }, + expected: { rclid: '7183717' }, + }, + { + title: 'should prioritize local storage over cookies', + setup: { + url: 'https://www.example.com/', + cookies: ['RoktTransactionId=67890'], + localStorage: { RoktTransactionId: '12345' }, + mockNow: 42, + }, + expected: { RoktTransactionId: '12345' }, + }, + ]; - expect(integrationCapture.clickIds).toEqual({ - RoktTransactionId: '12345', + ROKT_FULL_CAPTURE.forEach(({ title, setup, expected }) => { + it(title, () => { + expect(clickIdsAfterFullCaptureAllMode(setup)).toEqual(expected); }); }); }); From 0e4f824c8fea7edf6cc7db8edc61af3124259eac Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 12:09:39 -0700 Subject: [PATCH 23/24] fix(test): drop redundant cast in clickIdsAfterFullCaptureAllMode --- test/jest/integration-capture.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 7cd7bd33d..710b620e6 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -29,7 +29,7 @@ function clickIdsAfterFullCaptureAllMode(setup: FullCaptureSetup): Record; + return integrationCapture.clickIds ?? {}; } describe('Integration Capture', () => { From c5abf7d3a27d98cec7620f5228c8bd51d7c6d813 Mon Sep 17 00:00:00 2001 From: Joshuah Ciafardone Date: Thu, 14 May 2026 12:34:49 -0700 Subject: [PATCH 24/24] revert(test): use window instead of globalThis in integration capture tests Restores Window augmentation typing for mParticle (fixes rollup TS2352). Sonar may flag window again; acceptable tradeoff. --- test/jest/integration-capture.spec.ts | 134 +++++++++++++------------- test/src/tests-integration-capture.ts | 42 ++++---- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/test/jest/integration-capture.spec.ts b/test/jest/integration-capture.spec.ts index 710b620e6..b8ce33412 100644 --- a/test/jest/integration-capture.spec.ts +++ b/test/jest/integration-capture.spec.ts @@ -18,15 +18,15 @@ function clickIdsAfterFullCaptureAllMode(setup: FullCaptureSetup): Record { - globalThis.document.cookie = c; + window.document.cookie = c; }); if (ls) { for (const [key, val] of Object.entries(ls)) { - globalThis.localStorage.setItem(key, val); + window.localStorage.setItem(key, val); } } - globalThis.location.href = urlObj.href; - globalThis.location.search = urlObj.search; + window.location.href = urlObj.href; + window.location.search = urlObj.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); return integrationCapture.clickIds ?? {}; @@ -96,20 +96,20 @@ describe('Integration Capture', () => { }); describe('capture V2 modes gating in helpers', () => { - const originalLocation = globalThis.location as any; + const originalLocation = window.location as any; beforeEach(() => { - delete (globalThis as any).location; - (globalThis as any).location = { href: 'https://www.example.com/', search: '' } as any; + delete (window as any).location; + (window as any).location = { href: 'https://www.example.com/', search: '' } as any; deleteAllCookies(); - globalThis.localStorage.clear(); + window.localStorage.clear(); jest.restoreAllMocks(); }); afterEach(() => { - globalThis.location = originalLocation; + window.location = originalLocation; deleteAllCookies(); - globalThis.localStorage.clear(); + window.localStorage.clear(); }); const V2_MODE_HELPER_CASES: Array<{ @@ -187,12 +187,12 @@ describe('Integration Capture', () => { jest.spyOn(Date, 'now').mockImplementation(() => mockNow); } const urlObj = new URL(url); - globalThis.location.href = urlObj.href; - globalThis.location.search = urlObj.search; + window.location.href = urlObj.href; + window.location.search = urlObj.search; cookies.forEach((c) => { document.cookie = c; }); - globalThis.localStorage.setItem('RoktTransactionId', 'ls-rok'); + window.localStorage.setItem('RoktTransactionId', 'ls-rok'); const integrationCapture = new IntegrationCapture(captureMode); @@ -209,11 +209,11 @@ describe('Integration Capture', () => { }); describe('#capture', () => { - const originalLocation = globalThis.location; + const originalLocation = window.location; beforeEach(() => { - delete (globalThis as any).location; - (globalThis as any).location = { + delete (window as any).location; + (window as any).location = { href: '', search: '', assign: jest.fn(), @@ -225,8 +225,8 @@ describe('Integration Capture', () => { }); afterEach(() => { - globalThis.location = originalLocation; - globalThis.localStorage.clear(); + window.location = originalLocation; + window.localStorage.clear(); jest.restoreAllMocks(); }); @@ -255,13 +255,13 @@ describe('Integration Capture', () => { const url = new URL(`https://www.example.com/?${queryParams}`); - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = '_fbp=54321'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = '_fbp=54321'; + window.document.cookie = 'baz=qux'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -433,12 +433,12 @@ describe('Integration Capture', () => { 'https://www.example.com/?fbclid=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890' ); - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = 'baz=qux'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -452,14 +452,14 @@ describe('Integration Capture', () => { it('should pass the _fbc value unaltered', () => { const url = new URL('https://www.example.com/?foo=bar'); - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = '_fbc=fb.1.1554763741205.AbCdEfGhIjKlMnOpQrStUvWxYz1234567890'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = 'baz=qux'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -472,13 +472,13 @@ describe('Integration Capture', () => { it('should pass the _fbp value unaltered', () => { const url = new URL('https://www.example.com/?foo=bar'); - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = '_fbp=54321'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = '_fbp=54321'; + window.document.cookie = 'baz=qux'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -493,13 +493,13 @@ describe('Integration Capture', () => { const url = new URL('https://www.example.com/?fbclid=12345&'); - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = '_fbc=fb.1.23.654321'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = '_fbc=fb.1.23.654321'; + window.document.cookie = 'baz=qux'; - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -601,11 +601,11 @@ describe('Integration Capture', () => { }); describe('#captureQueryParams', () => { - const originalLocation = globalThis.location; + const originalLocation = window.location; beforeEach(() => { - delete (globalThis as any).location; - (globalThis as any).location = { + delete (window as any).location; + (window as any).location = { href: '', search: '', assign: jest.fn(), @@ -615,7 +615,7 @@ describe('Integration Capture', () => { }); afterEach(() => { - globalThis.location = originalLocation; + window.location = originalLocation; jest.restoreAllMocks(); }); @@ -626,8 +626,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?ttclid=12345&fbclid=67890&gclid=54321&rclid=7183717&rtid=54321' ); - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureQueryParams(); @@ -646,8 +646,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?invalidid=12345&foo=bar' ); - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureQueryParams(); @@ -659,8 +659,8 @@ describe('Integration Capture', () => { 'https://www.example.com/?fbclid=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890' ); - globalThis.location.href = url.href; - globalThis.location.search = url.search; + window.location.href = url.href; + window.location.search = url.search; const integrationCapture = new IntegrationCapture('all'); integrationCapture.capture(); @@ -681,10 +681,10 @@ describe('Integration Capture', () => { }); it('should capture specific cookies into clickIds object', () => { - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = '_fbp=54321'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = '_fbp=54321'; + window.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); @@ -695,9 +695,9 @@ describe('Integration Capture', () => { }); it('should capture _scid from cookies', () => { - globalThis.document.cookie = '_cookie1=4567'; - globalThis.document.cookie = '_scid=cookie1-from-cookie'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=4567'; + window.document.cookie = '_scid=cookie1-from-cookie'; + window.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); @@ -708,9 +708,9 @@ describe('Integration Capture', () => { }); it('should NOT capture cookies if they are not mapped', () => { - globalThis.document.cookie = '_cookie1=1234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = 'baz=qux'; + window.document.cookie = '_cookie1=1234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = 'baz=qux'; const integrationCapture = new IntegrationCapture('all'); const clickIds = integrationCapture.captureCookies(); diff --git a/test/src/tests-integration-capture.ts b/test/src/tests-integration-capture.ts index b4dad64f1..f61429baa 100644 --- a/test/src/tests-integration-capture.ts +++ b/test/src/tests-integration-capture.ts @@ -21,7 +21,7 @@ declare global { } } -const mParticle = globalThis.mParticle as IMParticleInstanceManager; +const mParticle = window.mParticle as IMParticleInstanceManager; /** Expected integration-capture custom flags from stubbed query params + _scid cookie */ function expectCapturedSnapchatAndPinterestFlags( @@ -74,10 +74,10 @@ function logCommercePurchaseAndGetEvent(customFlags: Record) { } function logThreeEventsUploadAndParseBatch(): Record { - globalThis.mParticle.logEvent('Test Event 1'); - globalThis.mParticle.logEvent('Test Event 2'); - globalThis.mParticle.logEvent('Test Event 3'); - globalThis.mParticle.upload(); + window.mParticle.logEvent('Test Event 1'); + window.mParticle.logEvent('Test Event 2'); + window.mParticle.logEvent('Test Event 3'); + window.mParticle.upload(); expect(fetchMock.calls().length).to.greaterThan(1); const lastCall = fetchMock.lastCall(); return JSON.parse(lastCall[1].body as string) as Record; @@ -145,22 +145,22 @@ describe('Integration Capture', () => { mpid: testMPID, is_logged_in: false }); - globalThis.mParticle.config.flags = { + window.mParticle.config.flags = { captureIntegrationSpecificIds: 'True', captureIntegrationSpecificIdsV2: 'all' }; - globalThis.document.cookie = '_cookie1=234'; - globalThis.document.cookie = '_cookie2=39895811.9165333198'; - globalThis.document.cookie = 'foo=bar'; - globalThis.document.cookie = '_fbp=54321'; - globalThis.document.cookie = 'baz=qux'; - globalThis.document.cookie = '_ttp=45670808'; - globalThis.document.cookie = '_scid=cookie1-value'; - mParticle.init(apiKey, globalThis.mParticle.config); + window.document.cookie = '_cookie1=234'; + window.document.cookie = '_cookie2=39895811.9165333198'; + window.document.cookie = 'foo=bar'; + window.document.cookie = '_fbp=54321'; + window.document.cookie = 'baz=qux'; + window.document.cookie = '_ttp=45670808'; + window.document.cookie = '_scid=cookie1-value'; + mParticle.init(apiKey, window.mParticle.config); await waitForCondition(hasIdentifyReturned); - const integrationCapture = globalThis.mParticle.getInstance()._IntegrationCapture; - // Mock the query params capture function because we cannot mock globalThis.location.href + const integrationCapture = window.mParticle.getInstance()._IntegrationCapture; + // Mock the query params capture function because we cannot mock window.location.href sinon.stub(integrationCapture, 'getQueryParams').returns({ fbclid: '1234', gclid: '234', @@ -212,7 +212,7 @@ describe('Integration Capture', () => { const eventName = kind === 'event' ? 'Test Event' : 'Test Page View'; const testEvent = findEventFromRequest(fetchMock.calls(), eventName); const initialTimestamp = - globalThis.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent).to.have.property('data'); if (kind === 'event') { @@ -239,7 +239,7 @@ describe('Integration Capture', () => { const testEvent = logCommercePurchaseAndGetEvent(customFlags); const initialTimestamp = - globalThis.mParticle.getInstance()._IntegrationCapture.initialTimestamp; + window.mParticle.getInstance()._IntegrationCapture.initialTimestamp; expect(testEvent.data.product_action).to.have.property( 'action', @@ -290,7 +290,7 @@ describe('Integration Capture', () => { it('should add captured integrations to batch as integration attributes without colliding with set integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - globalThis.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); const batch = logThreeEventsUploadAndParseBatch(); @@ -309,8 +309,8 @@ describe('Integration Capture', () => { it('should add captured integrations to batch as integration attributes, prioritizing passed in integration attributes', async () => { await waitForCondition(hasIdentityCallInflightReturned); - globalThis.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); - globalThis.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); + window.mParticle.setIntegrationAttribute(1277, { 'passbackconversiontrackingid': 'passed-in'}); + window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'}); const batch = logThreeEventsUploadAndParseBatch();