From 477b9ae55d7ebb30f9e14d0651ab024cbb52161f Mon Sep 17 00:00:00 2001 From: Jaissica Date: Fri, 16 Jan 2026 16:54:27 -0500 Subject: [PATCH 1/6] feat: log custom event logging for selectPlacement --- src/Rokt-Kit.js | 40 +++++++++++++++ test/src/tests.js | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index 1e11709..52d772d 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -15,6 +15,7 @@ var name = 'Rokt'; var moduleId = 181; +var EVENT_NAME_SELECT_PLACEMENTS = 'selectplacements'; var constructor = function () { var self = this; @@ -199,10 +200,13 @@ var constructor = function () { * @param {Object} options - The options object for selecting placements containing: * - identifier {string}: The placement identifier * - attributes {Object}: Optional attributes to merge with existing attributes + * - devPassedAttributes {Object}: original attributes passed by developer * @returns {Promise} A Promise resolving to the Rokt launcher's selectPlacements method with processed attributes */ function selectPlacements(options) { var attributes = (options && options.attributes) || {}; + var devPassedAttributes = + (options && options.devPassedAttributes) || {}; var placementAttributes = mergeObjects(self.userAttributes, attributes); var filters = self.filters || {}; @@ -255,9 +259,45 @@ var constructor = function () { attributes: selectPlacementsAttributes, }); + // Log custom event for selectPlacements call + logSelectPlacementsEvent( + devPassedAttributes, + selectPlacementsAttributes + ); + return self.launcher.selectPlacements(selectPlacementsOptions); } + /** + * Logs a custom event when selectPlacements is called + * This enables visibility and troubleshooting + * @param {Object} devPassedAttributes - The attributes passed by the developer + * @param {Object} selectPlacementsAttributes - The final merged attributes sent to Rokt + */ + function logSelectPlacementsEvent( + devPassedAttributes, + selectPlacementsAttributes + ) { + // Event type 8 corresponds to "Other" in mParticle's EventType enum + var EVENT_TYPE_OTHER = 8; + + // Build event attributes with both passed and final attributes as JSON strings + // devPassedAttributes: attributes passed by the developer + // selectPlacementsAttributes: final attributes sent to selectPlacements + var eventAttributes = { + devPassedAttributes: JSON.stringify(devPassedAttributes || {}), + selectPlacementsAttributes: JSON.stringify( + selectPlacementsAttributes || {} + ), + }; + + window.mParticle.logEvent( + EVENT_NAME_SELECT_PLACEMENTS, + EVENT_TYPE_OTHER, + eventAttributes + ); + } + /** * Enables optional Integration Launcher extensions before selecting placements * @param {string} extensionName - Name of the extension to enable diff --git a/test/src/tests.js b/test/src/tests.js index 0b75846..8ec01c0 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -88,6 +88,15 @@ describe('Rokt Forwarder', () => { mParticle.generateHash = function (input) { return 'hashed-<' + input + '>-value'; }; + // Mock for logEvent to capture custom event logging + mParticle.loggedEvents = []; + mParticle.logEvent = function (eventName, eventType, eventAttributes) { + mParticle.loggedEvents.push({ + eventName: eventName, + eventType: eventType, + eventAttributes: eventAttributes, + }); + }; // -------------------START EDITING BELOW:----------------------- var MockRoktForwarder = function () { var self = this; @@ -734,6 +743,7 @@ describe('Rokt Forwarder', () => { window.mParticle.Rokt.attachKitCalled = true; return Promise.resolve(); }; + mParticle.loggedEvents = []; window.mParticle.Rokt.setLocalSessionAttribute = function ( key, value @@ -2495,6 +2505,121 @@ describe('Rokt Forwarder', () => { ); }); }); + + describe('#logSelectPlacementsEvent', () => { + it('should log a custom event with devPassedAttributes and selectPlacementsAttributes', async () => { + await window.mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + } + ); + + await window.mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + devPassedAttributes: { + 'original-attr': 'original-value', + }, + }); + + mParticle.loggedEvents.length.should.equal(1); + mParticle.loggedEvents[0].eventName.should.equal( + 'selectplacements' + ); + mParticle.loggedEvents[0].eventType.should.equal(8); // EventType.Other + + const eventAttributes = + mParticle.loggedEvents[0].eventAttributes; + eventAttributes.should.have.property('devPassedAttributes'); + eventAttributes.should.have.property( + 'selectPlacementsAttributes' + ); + + // devPassedAttributes should contain original attributes from developer + const devPassedAttrs = JSON.parse( + eventAttributes.devPassedAttributes + ); + devPassedAttrs.should.deepEqual({ + 'original-attr': 'original-value', + }); + }); + + it('should include selectPlacementsAttributes with merged user attributes, identities, and mpid', async () => { + await window.mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + { + 'cached-user-attr': 'cached-value', + } + ); + + await window.mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + 'new-attr': 'new-value', + }, + devPassedAttributes: { + 'new-attr': 'new-value', + }, + }); + + const eventAttributes = + mParticle.loggedEvents[0].eventAttributes; + const selectPlacementsAttrs = JSON.parse( + eventAttributes.selectPlacementsAttributes + ); + + // selectPlacementsAttributes should include merged attributes and mpid + selectPlacementsAttrs.should.have.property('mpid', '123'); + selectPlacementsAttrs.should.have.property( + 'new-attr', + 'new-value' + ); + selectPlacementsAttrs.should.have.property( + 'cached-user-attr', + 'cached-value' + ); + }); + + it('should handle empty devPassedAttributes', async () => { + await window.mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {} + ); + + await window.mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + attr: 'value', + }, + }); + + mParticle.loggedEvents.length.should.equal(1); + const eventAttributes = + mParticle.loggedEvents[0].eventAttributes; + const devPassedAttrs = JSON.parse( + eventAttributes.devPassedAttributes + ); + devPassedAttrs.should.deepEqual({}); + }); + }); }); describe('#use', () => { From 2a0a5f30a358919a3e458ec76e99fc05044c8669 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Fri, 16 Jan 2026 17:06:50 -0500 Subject: [PATCH 2/6] add check in logSelectPlacementsEvent --- src/Rokt-Kit.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index 52d772d..2a92066 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -278,6 +278,12 @@ var constructor = function () { devPassedAttributes, selectPlacementsAttributes ) { + if ( + !window.mParticle || + typeof window.mParticle.logEvent !== 'function' + ) { + return; + } // Event type 8 corresponds to "Other" in mParticle's EventType enum var EVENT_TYPE_OTHER = 8; From f81b5792627fb5b2af8af221a65cb2b72bebd50e Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 21 Jan 2026 18:29:54 -0500 Subject: [PATCH 3/6] rename devPassedAttributes to debugAttributes, add helper to stringify object and update tests --- src/Rokt-Kit.js | 28 ++++++++++++++-------------- test/src/tests.js | 24 ++++++++++-------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index 2a92066..bb435eb 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -200,13 +200,12 @@ var constructor = function () { * @param {Object} options - The options object for selecting placements containing: * - identifier {string}: The placement identifier * - attributes {Object}: Optional attributes to merge with existing attributes - * - devPassedAttributes {Object}: original attributes passed by developer + * - debugAttributes {Object}: original attributes passed by developer * @returns {Promise} A Promise resolving to the Rokt launcher's selectPlacements method with processed attributes */ function selectPlacements(options) { var attributes = (options && options.attributes) || {}; - var devPassedAttributes = - (options && options.devPassedAttributes) || {}; + var debugAttributes = (options && options.debugAttributes) || {}; var placementAttributes = mergeObjects(self.userAttributes, attributes); var filters = self.filters || {}; @@ -260,10 +259,7 @@ var constructor = function () { }); // Log custom event for selectPlacements call - logSelectPlacementsEvent( - devPassedAttributes, - selectPlacementsAttributes - ); + logSelectPlacementsEvent(debugAttributes, selectPlacementsAttributes); return self.launcher.selectPlacements(selectPlacementsOptions); } @@ -271,11 +267,11 @@ var constructor = function () { /** * Logs a custom event when selectPlacements is called * This enables visibility and troubleshooting - * @param {Object} devPassedAttributes - The attributes passed by the developer + * @param {Object} debugAttributes - The attributes passed by the developer * @param {Object} selectPlacementsAttributes - The final merged attributes sent to Rokt */ function logSelectPlacementsEvent( - devPassedAttributes, + debugAttributes, selectPlacementsAttributes ) { if ( @@ -285,15 +281,15 @@ var constructor = function () { return; } // Event type 8 corresponds to "Other" in mParticle's EventType enum - var EVENT_TYPE_OTHER = 8; + var EVENT_TYPE_OTHER = window.mParticle.EventType.Other; // Build event attributes with both passed and final attributes as JSON strings - // devPassedAttributes: attributes passed by the developer + // debugAttributes: attributes passed by the developer // selectPlacementsAttributes: final attributes sent to selectPlacements var eventAttributes = { - devPassedAttributes: JSON.stringify(devPassedAttributes || {}), - selectPlacementsAttributes: JSON.stringify( - selectPlacementsAttributes || {} + debugAttributes: stringifyIfObject(debugAttributes), + selectPlacementsAttributes: stringifyIfObject( + selectPlacementsAttributes ), }; @@ -626,6 +622,10 @@ function isEmpty(value) { return value == null || !(Object.keys(value) || value).length; } +function stringifyIfObject(value) { + return isObject(value) ? JSON.stringify(value) : '{}'; +} + if (window && window.mParticle && window.mParticle.addForwarder) { window.mParticle.addForwarder({ name: name, diff --git a/test/src/tests.js b/test/src/tests.js index 8ec01c0..7f90826 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -2507,7 +2507,7 @@ describe('Rokt Forwarder', () => { }); describe('#logSelectPlacementsEvent', () => { - it('should log a custom event with devPassedAttributes and selectPlacementsAttributes', async () => { + it('should log a custom event with debugAttributes and selectPlacementsAttributes', async () => { await window.mParticle.forwarder.init( { accountId: '123456', @@ -2525,7 +2525,7 @@ describe('Rokt Forwarder', () => { attributes: { 'new-attr': 'new-value', }, - devPassedAttributes: { + debugAttributes: { 'original-attr': 'original-value', }, }); @@ -2538,16 +2538,14 @@ describe('Rokt Forwarder', () => { const eventAttributes = mParticle.loggedEvents[0].eventAttributes; - eventAttributes.should.have.property('devPassedAttributes'); + eventAttributes.should.have.property('debugAttributes'); eventAttributes.should.have.property( 'selectPlacementsAttributes' ); - // devPassedAttributes should contain original attributes from developer - const devPassedAttrs = JSON.parse( - eventAttributes.devPassedAttributes - ); - devPassedAttrs.should.deepEqual({ + // debugAttributes should contain original attributes from developer + const debugAttrs = JSON.parse(eventAttributes.debugAttributes); + debugAttrs.should.deepEqual({ 'original-attr': 'original-value', }); }); @@ -2570,7 +2568,7 @@ describe('Rokt Forwarder', () => { attributes: { 'new-attr': 'new-value', }, - devPassedAttributes: { + debugAttributes: { 'new-attr': 'new-value', }, }); @@ -2593,7 +2591,7 @@ describe('Rokt Forwarder', () => { ); }); - it('should handle empty devPassedAttributes', async () => { + it('should handle empty debugAttributes', async () => { await window.mParticle.forwarder.init( { accountId: '123456', @@ -2614,10 +2612,8 @@ describe('Rokt Forwarder', () => { mParticle.loggedEvents.length.should.equal(1); const eventAttributes = mParticle.loggedEvents[0].eventAttributes; - const devPassedAttrs = JSON.parse( - eventAttributes.devPassedAttributes - ); - devPassedAttrs.should.deepEqual({}); + const debugAttrs = JSON.parse(eventAttributes.debugAttributes); + debugAttrs.should.deepEqual({}); }); }); }); From 5297654520ae083bf7c07cc6138e59585f5edd7f Mon Sep 17 00:00:00 2001 From: Jaissica Date: Wed, 21 Jan 2026 18:51:00 -0500 Subject: [PATCH 4/6] fix typo and update tests --- src/Rokt-Kit.js | 6 ++++-- test/src/tests.js | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index bb435eb..a67c8e2 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -200,7 +200,7 @@ var constructor = function () { * @param {Object} options - The options object for selecting placements containing: * - identifier {string}: The placement identifier * - attributes {Object}: Optional attributes to merge with existing attributes - * - debugAttributes {Object}: original attributes passed by developer + * - debugAttributes {Object}: Original attributes passed by developer * @returns {Promise} A Promise resolving to the Rokt launcher's selectPlacements method with processed attributes */ function selectPlacements(options) { @@ -281,7 +281,9 @@ var constructor = function () { return; } // Event type 8 corresponds to "Other" in mParticle's EventType enum - var EVENT_TYPE_OTHER = window.mParticle.EventType.Other; + var EVENT_TYPE_OTHER = + (window.mParticle.EventType && window.mParticle.EventType.Other) || + 8; // Build event attributes with both passed and final attributes as JSON strings // debugAttributes: attributes passed by the developer diff --git a/test/src/tests.js b/test/src/tests.js index 7f90826..962f1ea 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -2615,6 +2615,32 @@ describe('Rokt Forwarder', () => { const debugAttrs = JSON.parse(eventAttributes.debugAttributes); debugAttrs.should.deepEqual({}); }); + + it('should skip logging when mParticle.logEvent is not available', async () => { + var originalLogEvent = window.mParticle.logEvent; + window.mParticle.logEvent = undefined; + + await window.mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {} + ); + + await window.mParticle.forwarder.selectPlacements({ + identifier: 'test-placement', + attributes: { + attr: 'value', + }, + }); + + window.Rokt.selectPlacementsCalled.should.equal(true); + mParticle.loggedEvents.length.should.equal(0); + window.mParticle.logEvent = originalLogEvent; + }); }); }); From 3bb12616e25daf862b8bf480369a4d05da9d400c Mon Sep 17 00:00:00 2001 From: Jaissica Date: Fri, 23 Jan 2026 11:03:44 -0500 Subject: [PATCH 5/6] rename debugAttributes to initialAttributes and selectPlacementsAttributes to finalAttributes --- src/Rokt-Kit.js | 20 +++++++++----------- test/src/tests.js | 45 +++++++++++++++++++++------------------------ 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index a67c8e2..18c82bf 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -200,12 +200,12 @@ var constructor = function () { * @param {Object} options - The options object for selecting placements containing: * - identifier {string}: The placement identifier * - attributes {Object}: Optional attributes to merge with existing attributes - * - debugAttributes {Object}: Original attributes passed by developer + * - initialAttributes {Object}: Original attributes passed by developer * @returns {Promise} A Promise resolving to the Rokt launcher's selectPlacements method with processed attributes */ function selectPlacements(options) { var attributes = (options && options.attributes) || {}; - var debugAttributes = (options && options.debugAttributes) || {}; + var initialAttributes = (options && options.initialAttributes) || {}; var placementAttributes = mergeObjects(self.userAttributes, attributes); var filters = self.filters || {}; @@ -259,7 +259,7 @@ var constructor = function () { }); // Log custom event for selectPlacements call - logSelectPlacementsEvent(debugAttributes, selectPlacementsAttributes); + logSelectPlacementsEvent(initialAttributes, selectPlacementsAttributes); return self.launcher.selectPlacements(selectPlacementsOptions); } @@ -267,11 +267,11 @@ var constructor = function () { /** * Logs a custom event when selectPlacements is called * This enables visibility and troubleshooting - * @param {Object} debugAttributes - The attributes passed by the developer + * @param {Object} initialAttributes - The attributes passed by the developer * @param {Object} selectPlacementsAttributes - The final merged attributes sent to Rokt */ function logSelectPlacementsEvent( - debugAttributes, + initialAttributes, selectPlacementsAttributes ) { if ( @@ -286,13 +286,11 @@ var constructor = function () { 8; // Build event attributes with both passed and final attributes as JSON strings - // debugAttributes: attributes passed by the developer - // selectPlacementsAttributes: final attributes sent to selectPlacements + // initialAttributes: attributes passed by the developer + // finalAttributes: final attributes sent to selectPlacements var eventAttributes = { - debugAttributes: stringifyIfObject(debugAttributes), - selectPlacementsAttributes: stringifyIfObject( - selectPlacementsAttributes - ), + initialAttributes: stringifyIfObject(initialAttributes), + finalAttributes: stringifyIfObject(selectPlacementsAttributes), }; window.mParticle.logEvent( diff --git a/test/src/tests.js b/test/src/tests.js index 962f1ea..90a5192 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -2507,7 +2507,7 @@ describe('Rokt Forwarder', () => { }); describe('#logSelectPlacementsEvent', () => { - it('should log a custom event with debugAttributes and selectPlacementsAttributes', async () => { + it('should log a custom event with initialAttributes and finalAttributes', async () => { await window.mParticle.forwarder.init( { accountId: '123456', @@ -2525,7 +2525,7 @@ describe('Rokt Forwarder', () => { attributes: { 'new-attr': 'new-value', }, - debugAttributes: { + initialAttributes: { 'original-attr': 'original-value', }, }); @@ -2538,19 +2538,19 @@ describe('Rokt Forwarder', () => { const eventAttributes = mParticle.loggedEvents[0].eventAttributes; - eventAttributes.should.have.property('debugAttributes'); - eventAttributes.should.have.property( - 'selectPlacementsAttributes' - ); + eventAttributes.should.have.property('initialAttributes'); + eventAttributes.should.have.property('finalAttributes'); - // debugAttributes should contain original attributes from developer - const debugAttrs = JSON.parse(eventAttributes.debugAttributes); - debugAttrs.should.deepEqual({ + // initialAttributes should contain original attributes from developer + const initialAttrs = JSON.parse( + eventAttributes.initialAttributes + ); + initialAttrs.should.deepEqual({ 'original-attr': 'original-value', }); }); - it('should include selectPlacementsAttributes with merged user attributes, identities, and mpid', async () => { + it('should include finalAttributes with merged user attributes, identities, and mpid', async () => { await window.mParticle.forwarder.init( { accountId: '123456', @@ -2568,30 +2568,25 @@ describe('Rokt Forwarder', () => { attributes: { 'new-attr': 'new-value', }, - debugAttributes: { + initialAttributes: { 'new-attr': 'new-value', }, }); const eventAttributes = mParticle.loggedEvents[0].eventAttributes; - const selectPlacementsAttrs = JSON.parse( - eventAttributes.selectPlacementsAttributes - ); + const finalAttrs = JSON.parse(eventAttributes.finalAttributes); - // selectPlacementsAttributes should include merged attributes and mpid - selectPlacementsAttrs.should.have.property('mpid', '123'); - selectPlacementsAttrs.should.have.property( - 'new-attr', - 'new-value' - ); - selectPlacementsAttrs.should.have.property( + // finalAttributes should include merged attributes and mpid + finalAttrs.should.have.property('mpid', '123'); + finalAttrs.should.have.property('new-attr', 'new-value'); + finalAttrs.should.have.property( 'cached-user-attr', 'cached-value' ); }); - it('should handle empty debugAttributes', async () => { + it('should handle empty initialAttributes', async () => { await window.mParticle.forwarder.init( { accountId: '123456', @@ -2612,8 +2607,10 @@ describe('Rokt Forwarder', () => { mParticle.loggedEvents.length.should.equal(1); const eventAttributes = mParticle.loggedEvents[0].eventAttributes; - const debugAttrs = JSON.parse(eventAttributes.debugAttributes); - debugAttrs.should.deepEqual({}); + const initialAttrs = JSON.parse( + eventAttributes.initialAttributes + ); + initialAttrs.should.deepEqual({}); }); it('should skip logging when mParticle.logEvent is not available', async () => { From f76a5f98ea5e0dcb1eee846cef181177b36163b7 Mon Sep 17 00:00:00 2001 From: Jaissica Date: Fri, 23 Jan 2026 14:18:40 -0500 Subject: [PATCH 6/6] cleanup EVENT_TYPE_OTHER var --- src/Rokt-Kit.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Rokt-Kit.js b/src/Rokt-Kit.js index 18c82bf..3912058 100644 --- a/src/Rokt-Kit.js +++ b/src/Rokt-Kit.js @@ -280,10 +280,8 @@ var constructor = function () { ) { return; } - // Event type 8 corresponds to "Other" in mParticle's EventType enum - var EVENT_TYPE_OTHER = - (window.mParticle.EventType && window.mParticle.EventType.Other) || - 8; + + var EVENT_TYPE_OTHER = window.mParticle.EventType.Other; // Build event attributes with both passed and final attributes as JSON strings // initialAttributes: attributes passed by the developer