Skip to content
103 changes: 90 additions & 13 deletions src/Rokt-Kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

var roktLauncherScript = 'https://apps.rokt.com/wsdk/integrations/launcher.js';

var name = 'Rokt';
var moduleId = 181;

var ROKT_EXTENSIONS = {
'Coupon on Signup Extension Detection': 'cos-extension-detection',
'Experiment Monitoring': 'experiment-monitoring',
'Sponsored Payments Apple Pay': 'sponsored-payments-apple-pay',
'Realtime Conversion Promotion': 'realtime-conversion-promotion',
};

var constructor = function () {
var self = this;

Expand All @@ -29,6 +34,20 @@ var constructor = function () {
self.filters = {};
self.filteredUser = {};
self.userAttributes = {};
self.testHelpers = null;

/**
* Generates the Rokt launcher script URL with optional extensions
* @param {Array<string>} extensions - List of extension query parameters to append
* @returns {string} The complete launcher script URL
*/
function generateLauncherScript(extensions) {
var baseUrl = 'https://apps.rokt.com/wsdk/integrations/launcher.js';
if (!extensions || extensions.length === 0) {
return baseUrl;
}
return baseUrl + '?extensions=' + extensions.join(',');
}

/**
* Passes attributes to the Rokt Web SDK for client-side hashing
Expand All @@ -53,10 +72,16 @@ var constructor = function () {
filteredUserAttributes
) {
var accountId = settings.accountId;
var roktExtensions = extractRoktExtensions(settings.roktExtensions);
self.userAttributes = filteredUserAttributes;
self.onboardingExpProvider = settings.onboardingExpProvider;

if (testMode) {
// Initialize test helpers only in test mode
self.testHelpers = {
generateLauncherScript: generateLauncherScript,
extractRoktExtensions: extractRoktExtensions,
};
attachLauncher(accountId);
return;
}
Expand All @@ -65,7 +90,7 @@ var constructor = function () {
var target = document.head || document.body;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = roktLauncherScript;
script.src = generateLauncherScript(roktExtensions);
script.async = true;
script.crossOrigin = 'anonymous';
script.fetchPriority = 'high';
Expand Down Expand Up @@ -135,14 +160,11 @@ var constructor = function () {

self.userAttributes = filteredAttributes;

var optimizelyAttributes =
self.onboardingExpProvider === 'Optimizely'
? fetchOptimizely()
: {};
var experimentAttributes = formatExperimentAttributes(attributes);

var selectPlacementsAttributes = mergeObjects(
filteredAttributes,
optimizelyAttributes,
experimentAttributes,
{
mpid: mpid,
}
Expand All @@ -155,6 +177,22 @@ var constructor = function () {
self.launcher.selectPlacements(selectPlacementsOptions);
}

/**
* Sets extension data for Rokt Web SDK
* @param {Object} partnerExtensionData - The extension data object containing:
* - [extensionName] {string}: Name of the extension
* - [extensionName].options {Object}: Key-value pairs of options for the extension
* @returns {void} Nothing is returned
*/
function setExtensionData(partnerExtensionData) {
if (!isInitialized()) {
console.error('Rokt Kit: Not initialized');
return;
}

window.Rokt.setExtensionData(partnerExtensionData);
}

function onUserIdentified(filteredUser) {
self.filteredUser = filteredUser;
self.userAttributes = filteredUser.getAllUserAttributes();
Expand Down Expand Up @@ -210,6 +248,22 @@ var constructor = function () {
});
}

function formatExperimentAttributes(attributes) {
var PREFIX = 'rokt.partnerexperiment.';
var EXPERIMENT_ID_KEY = PREFIX + 'experimentid';
var BUCKET_ID_KEY = PREFIX + 'bucketid';
var USER_ID_KEY = PREFIX + 'userid';

if (self.onboardingExpProvider === 'Optimizely') {
return fetchOptimizely(attributes);
}

var result = {};
result[PREFIX + attributes[EXPERIMENT_ID_KEY] + '.bucketid'] =
attributes[BUCKET_ID_KEY];
result['rokt.clientcustomerid'] = attributes[USER_ID_KEY];
return result;
}
// mParticle Kit Callback Methods
function fetchOptimizely() {
var forwarders = window.mParticle
Expand All @@ -236,14 +290,13 @@ var constructor = function () {
acc,
expId
) {
acc[
'rokt.custom.optimizely.experiment.' +
expId +
'.variationId'
] = optimizelyState.getVariationMap()[expId].id;
acc['rokt.partnerexperiment.' + expId + '.bucketid'] =
optimizelyState.getVariationMap()[expId].id;
return acc;
},
{});
var visitorId = window.optimizely.get('visitor').visitorId;
activeExperiments['rokt.clientcustomerid'] = visitorId;
return activeExperiments;
}
} catch (error) {
Expand All @@ -258,6 +311,7 @@ var constructor = function () {

// Kit Callback Methods
this.init = initForwarder;
this.setExtensionData = setExtensionData;
this.setUserAttribute = setUserAttribute;
this.onUserIdentified = onUserIdentified;
this.removeUserAttribute = removeUserAttribute;
Expand Down Expand Up @@ -325,6 +379,29 @@ function mergeObjects() {
return resObj;
}

function parseSettingsString(settingsString) {
try {
return JSON.parse(settingsString.replace(/&quot;/g, '"'));
} catch (error) {
throw new Error('Settings string contains invalid JSON');
}
}

function extractRoktExtensions(settingsString) {
var settings = settingsString ? parseSettingsString(settingsString) : [];

var roktExtensions = [];
for (var i = 0; i < settings.length; i++) {
var extensionName = settings[i].value;
var mappedExtension = ROKT_EXTENSIONS[extensionName];
if (mappedExtension) {
roktExtensions.push(mappedExtension);
}
}

return roktExtensions;
}

if (window && window.mParticle && window.mParticle.addForwarder) {
window.mParticle.addForwarder({
name: name,
Expand Down
97 changes: 95 additions & 2 deletions test/src/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ describe('Rokt Forwarder', () => {

this.initializeCalled = false;
this.isInitialized = false;

this.accountId = null;
this.sandbox = null;
this.integrationName = null;

this.createLauncherCalled = false;

this.createLauncher = function (options) {
self.accountId = options.accountId;
self.integrationName = options.integrationName;
Expand Down Expand Up @@ -756,4 +755,98 @@ describe('Rokt Forwarder', () => {
});
});
});

describe('#generateLauncherScript', () => {
const baseUrl = 'https://apps.rokt.com/wsdk/integrations/launcher.js';

beforeEach(() => {
window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true
);
});

it('should return base URL when no extensions are provided', () => {
const url =
window.mParticle.forwarder.testHelpers.generateLauncherScript(
[]
);
url.should.equal(baseUrl);
});

it('should return base URL when extensions is null or undefined', () => {
window.mParticle.forwarder.testHelpers
.generateLauncherScript(null)
.should.equal(baseUrl);

window.mParticle.forwarder.testHelpers
.generateLauncherScript(undefined)
.should.equal(baseUrl);
});

it('should correctly append a single extension', () => {
const url =
window.mParticle.forwarder.testHelpers.generateLauncherScript([
'cos-extension-detection',
]);
url.should.equal(baseUrl + '?extensions=cos-extension-detection');
});

it('should correctly append multiple extensions', () => {
const url =
window.mParticle.forwarder.testHelpers.generateLauncherScript([
'cos-extension-detection',
'experiment-monitoring',
'sponsored-payments-apple-pay',
]);
url.should.equal(
baseUrl +
'?extensions=cos-extension-detection,' +
'experiment-monitoring,' +
'sponsored-payments-apple-pay'
);
});
});

describe('#roktExtensions', () => {
beforeEach(() => {
window.Rokt = new MockRoktForwarder();
window.mParticle.Rokt = window.Rokt;
});

describe('extractRoktExtensions', () => {
it('should correctly map known extension names to their query parameters', async () => {
window.mParticle.forwarder.testHelpers
.extractRoktExtensions(
'[{&quot;value&quot;:&quot;Coupon on Signup Extension Detection&quot;},' +
'{&quot;value&quot;:&quot;Experiment Monitoring&quot;},' +
'{&quot;value&quot;:&quot;Sponsored Payments Apple Pay&quot;},' +
'{&quot;value&quot;:&quot;Realtime Conversion Promotion&quot;}]'
)
.should.deepEqual([
'cos-extension-detection',
'experiment-monitoring',
'sponsored-payments-apple-pay',
'realtime-conversion-promotion',
]);
});

it('should ignore unknown or invalid extensions', async () => {
window.mParticle.forwarder.testHelpers
.extractRoktExtensions(
'[{&quot;value&quot;:&quot;Unknown Extension&quot;},' +
'{&quot;value&quot;:&quot;Experiment Monitoring&quot;},' +
'{&quot;invalid_key&quot;:&quot;Invalid Format&quot;},' +
'{&quot;value&quot;:&quot;Sponsored Payments Apple Pay&quot;}]'
)
.should.deepEqual([
'experiment-monitoring',
'sponsored-payments-apple-pay',
]);
});
});
});
});
Loading