-
Notifications
You must be signed in to change notification settings - Fork 14
[CDX-470] Add additionalTrackingKeys option
#472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
bfb3d45
ad68a18
35750b3
b2b471b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16345,4 +16345,39 @@ describe(`ConstructorIO - Tracker${bundledDescriptionSuffix}`, () => { | |
| ).to.equal(true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('additionalTrackingKeys', () => { | ||
| it('Should send tracking events to both primary and additional keys', (done) => { | ||
| const additionalKey = 'extra-test-key'; | ||
| const { tracker } = new ConstructorIO({ | ||
| apiKey: testApiKey, | ||
| fetch: fetchSpy, | ||
| ...requestQueueOptions, | ||
| additionalTrackingKeys: [additionalKey], | ||
| }); | ||
|
|
||
| let callCount = 0; | ||
|
|
||
| const checkComplete = () => { | ||
| callCount += 1; | ||
|
|
||
| if (callCount === 2) { | ||
| expect(fetchSpy).to.have.been.calledTwice; | ||
|
constructor-claude-bedrock[bot] marked this conversation as resolved.
constructor-claude-bedrock[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important Issue: The integration test relies on Use const localSpy = sinon.spy(fetch);
const { tracker } = new ConstructorIO({
apiKey: testApiKey,
fetch: localSpy,
...
});
// then assert localSpy.getCall(0) / localSpy.getCall(1)Also, |
||
|
|
||
| const firstCallUrl = fetchSpy.getCall(0).args[0]; | ||
| const secondCallUrl = fetchSpy.getCall(1).args[0]; | ||
|
|
||
| expect(firstCallUrl).to.contain(`key=${testApiKey}`); | ||
| expect(secondCallUrl).to.contain(`key=${additionalKey}`); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also check for |
||
|
|
||
| done(); | ||
| } | ||
| }; | ||
|
|
||
| tracker.on('success', checkComplete); | ||
| tracker.on('error', checkComplete); | ||
|
|
||
| expect(tracker.trackSessionStartV2()).to.equal(true); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -318,6 +318,121 @@ describe('ConstructorIO - Utils - Request Queue', function utilsRequestQueue() { | |
| }); | ||
| }); | ||
|
|
||
| describe('additionalTrackingKeys', () => { | ||
| let defaultAgent; | ||
| let cleanup; | ||
|
|
||
| before(() => { | ||
| helpers.clearStorage(); | ||
| }); | ||
|
|
||
| beforeEach(() => { | ||
| global.CLIENT_VERSION = 'cio-mocha'; | ||
| cleanup = jsdom(); | ||
| defaultAgent = window.navigator.userAgent; | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| window.navigator.__defineGetter__('userAgent', () => defaultAgent); | ||
| delete global.CLIENT_VERSION; | ||
| cleanup(); | ||
| helpers.clearStorage(); | ||
| }); | ||
|
|
||
| it('Should add duplicate requests for each additional tracking key', () => { | ||
| store.session.set(humanityStorageKey, true); | ||
| const requests = new RequestQueue({ | ||
| sendTrackingEvents: true, | ||
| trackingSendDelay: 1, | ||
| apiKey: 'primary-key', | ||
| additionalTrackingKeys: ['extra-key-1', 'extra-key-2'], | ||
| }); | ||
|
|
||
| requests.queue('https://ac.cnstrc.com/behavior?action=session_start&key=primary-key&_dt=123', 'POST', { action: 'session_start', key: 'primary-key' }); | ||
|
|
||
| const queue = RequestQueue.get(); | ||
| expect(queue).to.be.an('array').length(3); | ||
|
|
||
| // Primary request | ||
| expect(queue[0].url).to.contain('key=primary-key'); | ||
| expect(queue[0].body.key).to.equal('primary-key'); | ||
|
|
||
| // First additional key | ||
| expect(queue[1].url).to.contain('key=extra-key-1'); | ||
| expect(queue[1].url).to.not.contain('key=primary-key'); | ||
| expect(queue[1].body.key).to.equal('extra-key-1'); | ||
|
constructor-claude-bedrock[bot] marked this conversation as resolved.
constructor-claude-bedrock[bot] marked this conversation as resolved.
|
||
|
|
||
| // Second additional key | ||
| expect(queue[2].url).to.contain('key=extra-key-2'); | ||
| expect(queue[2].url).to.not.contain('key=primary-key'); | ||
| expect(queue[2].body.key).to.equal('extra-key-2'); | ||
| }); | ||
|
|
||
| it('Should not add duplicates when additionalTrackingKeys is an empty array', () => { | ||
| store.session.set(humanityStorageKey, true); | ||
| const requests = new RequestQueue({ | ||
| sendTrackingEvents: true, | ||
| trackingSendDelay: 1, | ||
| apiKey: 'primary-key', | ||
| additionalTrackingKeys: [], | ||
| }); | ||
|
|
||
| requests.queue('https://ac.cnstrc.com/behavior?action=session_start&key=primary-key&_dt=123'); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important Issue: The GET test ( |
||
|
|
||
| expect(RequestQueue.get()).to.be.an('array').length(1); | ||
| }); | ||
|
|
||
| it('Should not add duplicates when additionalTrackingKeys is not provided', () => { | ||
| store.session.set(humanityStorageKey, true); | ||
| const requests = new RequestQueue({ | ||
| sendTrackingEvents: true, | ||
| trackingSendDelay: 1, | ||
| apiKey: 'primary-key', | ||
| }); | ||
|
|
||
| requests.queue('https://ac.cnstrc.com/behavior?action=session_start&key=primary-key&_dt=123'); | ||
|
|
||
| expect(RequestQueue.get()).to.be.an('array').length(1); | ||
| }); | ||
|
|
||
| it('Should add duplicate GET requests without a body', () => { | ||
| store.session.set(humanityStorageKey, true); | ||
| const requests = new RequestQueue({ | ||
| sendTrackingEvents: true, | ||
| trackingSendDelay: 1, | ||
| apiKey: 'primary-key', | ||
| additionalTrackingKeys: ['extra-key-1'], | ||
| }); | ||
|
|
||
| requests.queue('https://ac.cnstrc.com/behavior?action=session_start&key=primary-key&_dt=123'); | ||
|
|
||
| const queue = RequestQueue.get(); | ||
| expect(queue).to.be.an('array').length(2); | ||
|
|
||
| expect(queue[0].url).to.contain('key=primary-key'); | ||
| expect(queue[1].url).to.contain('key=extra-key-1'); | ||
| expect(queue[1].url).to.contain('action=session_start'); | ||
| expect(queue[1].body.key).to.equal('extra-key-1'); | ||
| }); | ||
|
|
||
| it('Should skip invalid entries in additionalTrackingKeys', () => { | ||
| store.session.set(humanityStorageKey, true); | ||
| const requests = new RequestQueue({ | ||
| sendTrackingEvents: true, | ||
| trackingSendDelay: 1, | ||
| apiKey: 'primary-key', | ||
| additionalTrackingKeys: ['valid-key', '', null, 123, 'another-valid-key'], | ||
| }); | ||
|
|
||
| requests.queue('https://ac.cnstrc.com/behavior?action=session_start&key=primary-key&_dt=123', 'POST', { action: 'session_start', key: 'primary-key' }); | ||
|
|
||
| const queue = RequestQueue.get(); | ||
| expect(queue).to.be.an('array').length(3); | ||
| expect(queue[1].url).to.contain('key=valid-key'); | ||
| expect(queue[2].url).to.contain('key=another-valid-key'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('send', () => { | ||
| let fetchSpy = null; | ||
| let cleanup; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,6 +93,7 @@ class ConstructorIO { | |
| beaconMode, | ||
| networkParameters, | ||
| humanityCheckLocation, | ||
| additionalTrackingKeys, | ||
|
constructor-claude-bedrock[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: |
||
| } = options; | ||
|
Comment on lines
+97
to
98
|
||
|
|
||
| if (!apiKey || typeof apiKey !== 'string') { | ||
|
|
@@ -141,6 +142,7 @@ class ConstructorIO { | |
| beaconMode: (beaconMode === false) ? false : true, // Defaults to 'true', | ||
| networkParameters: networkParameters || {}, | ||
| humanityCheckLocation: humanityCheckLocation || 'session', | ||
| additionalTrackingKeys, | ||
| }; | ||
|
|
||
| // Expose global modules | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,28 @@ class RequestQueue { | |
| body, | ||
| networkParameters, | ||
| }); | ||
|
|
||
| // Duplicate request for each additional tracking key | ||
| const additionalKeys = this.options?.additionalTrackingKeys; | ||
|
|
||
| if (Array.isArray(additionalKeys) && additionalKeys.length) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big deal but can we:
|
||
| const encodedOriginalKey = encodeURIComponent(this.options.apiKey); | ||
|
|
||
| const validKeys = additionalKeys.filter((key) => key && typeof key === 'string'); | ||
|
|
||
| validKeys.forEach((additionalKey) => { | ||
| const encodedKey = encodeURIComponent(additionalKey); | ||
| const swappedUrl = url.replace(`key=${encodedOriginalKey}`, `key=${encodedKey}`); | ||
|
Copilot marked this conversation as resolved.
Outdated
|
||
|
|
||
| queue.push({ | ||
| url: obfuscatePiiRequest(swappedUrl), | ||
| method, | ||
| body: { ...body, key: additionalKey }, | ||
| networkParameters, | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| RequestQueue.set(queue); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add a test for verifying the body of the requests are the same in the duplicate request?