Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions src/Rokt-Kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,32 @@ var constructor = function () {
}
}

/**
* Adds user identities to the attributes object
* @param {Object} attributes - The attributes object to add identities to
* @param {Object} filteredUser - The filtered user object containing identities
* @returns {Object} The attributes object with added identities
*/
function addIdentityAttributes(attributes, filteredUser) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the purpose of this code change is to extract the user identities into the selectPlacement attributes, this function should a wrapper around filteredUser.getUserIdentities().userIdentities that simply returns the identities to be merged later.

It shouldn't be mutating the attributes at all, which can lead to side effects.

if (!filteredUser || !filteredUser.getUserIdentities) {
return attributes;
}

var userIdentities = filteredUser.getUserIdentities().userIdentities;
if (!userIdentities) {
return attributes;
}

for (var identityKey in userIdentities) {
if (userIdentities.hasOwnProperty(identityKey)) {
var identityValue = userIdentities[identityKey];
attributes[identityKey] = identityValue;
}
}

return attributes;
}

/**
* Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options
* @see https://docs.rokt.com/developers/integration-guides/web/library/select-placements-options/
Expand Down Expand Up @@ -160,6 +186,12 @@ var constructor = function () {
? fetchOptimizely()
: {};

// Add user identities to the attributes
filteredAttributes = addIdentityAttributes(
filteredAttributes,
filteredUser
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're merging all the different user attributes below, so I think instead of mutating the existing filtered attributes, we should create a new object that will be merged below. I think this would make logging and debugging easier in the future.

Also, it looks like you're just adding the user identities into the select placement attributes so you really don't need to modify the filtered attributes (i think).

You can just pull the identities out the of the user and just add them into the select placements attributes.

        var filteredUserIdentities = filteredUser.getUserIdentities().userIdentities;

        // Then below:
        var selectPlacementsAttributes = mergeObjects(
            filteredAttributes,
            filteredUserIdentities,
            optimizelyAttributes,
            {
                mpid: mpid,
            }
        );


var selectPlacementsAttributes = mergeObjects(
filteredAttributes,
optimizelyAttributes,
Expand All @@ -177,6 +209,7 @@ var constructor = function () {

function onUserIdentified(filteredUser) {
self.filteredUser = filteredUser;
self.filters.filteredUser = filteredUser;
Comment thread
alexs-mparticle marked this conversation as resolved.
self.userAttributes = filteredUser.getAllUserAttributes();
}

Expand All @@ -200,7 +233,6 @@ var constructor = function () {
.then(function (launcher) {
// Assign the launcher to a global variable for later access
window.Rokt.currentLauncher = launcher;

// Locally cache the launcher and filters
self.launcher = launcher;

Expand All @@ -218,7 +250,6 @@ var constructor = function () {
self.filteredUser = roktFilters.filteredUser;
}
Comment thread
alexs-mparticle marked this conversation as resolved.
}

// Attaches the kit to the Rokt manager
window.mParticle.Rokt.attachKit(self);

Expand Down
308 changes: 307 additions & 1 deletion test/src/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ describe('Rokt Forwarder', () => {
{}
);

await waitForCondition(() => window.mParticle.Rokt.attachKitCalled);
// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

window.mParticle.Rokt.kit.filters.should.deepEqual({
userAttributesFilters: [],
Expand Down Expand Up @@ -620,6 +623,309 @@ describe('Rokt Forwarder', () => {
},
});
});

describe('Identity handling', () => {
Comment thread
rmi22186 marked this conversation as resolved.
beforeEach(() => {
window.Rokt = new MockRoktForwarder();
window.mParticle.Rokt = window.Rokt;
window.mParticle.Rokt.attachKitCalled = false;
window.mParticle.Rokt.attachKit = async (kit) => {
window.mParticle.Rokt.attachKitCalled = true;
window.mParticle.Rokt.kit = kit;
Promise.resolve();
};
window.mParticle.forwarder.launcher = {
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions = options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
};
});

it('should handle case when userIdentities is null but userAttributes exist', async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should handle case when userIdentities is null but userAttributes exist', async () => {
it('should send userAttributes if userIdentities is null but userAttributes exists', async () => {

window.mParticle.Rokt.filters = {
userAttributeFilters: [],
filterUserAttributes: function (attributes) {
return attributes;
},
filteredUser: {
getMPID: function () {
return 'abc';
},
getUserIdentities: function () {
return { userIdentities: {} };
},
},
};

// Set up the createLauncher to properly resolve asynchronously
window.Rokt.createLauncher = async function () {
return Promise.resolve({
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions =
options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
});
};

await window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true,
null,
{
'test-attribute': 'test-value',
}
);

// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

await window.mParticle.forwarder.selectPlacements({
identifier: 'test-placement',
attributes: {},
});

window.Rokt.selectPlacementsOptions.attributes.should.deepEqual(
{
'test-attribute': 'test-value',
mpid: 'abc',
}
);
});

it('should handle case when userAttributes is null but userIdentities exist', async () => {
Comment thread
rmi22186 marked this conversation as resolved.
Outdated
window.mParticle.Rokt.filters = {
userAttributeFilters: [],
filterUserAttributes: function () {
return {};
},
filteredUser: {
getMPID: function () {
return '234';
},
getUserIdentities: function () {
return {
userIdentities: {
customerid: 'customer123',
email: 'test@example.com',
},
};
},
},
};

// Set up the createLauncher to properly resolve asynchronously
window.Rokt.createLauncher = async function () {
return Promise.resolve({
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions =
options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
});
};
await window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true,
null,
{}
);
// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

await window.mParticle.forwarder.selectPlacements({
identifier: 'test-placement',
attributes: {},
});

window.Rokt.selectPlacementsOptions.attributes.should.deepEqual(
{
customerid: 'customer123',
email: 'test@example.com',
mpid: '234',
}
);
});

it('should handle case when both userAttributes and userIdentities exist', async () => {
Comment thread
rmi22186 marked this conversation as resolved.
Outdated
window.mParticle.Rokt.filters = {
userAttributeFilters: [],
filterUserAttributes: function (attributes) {
return attributes;
},
filteredUser: {
getMPID: function () {
return '123';
},
getUserIdentities: function () {
return {
userIdentities: {
customerid: 'customer123',
email: 'test@example.com',
},
};
},
},
};

// Set up the createLauncher to properly resolve asynchronously
window.Rokt.createLauncher = async function () {
return Promise.resolve({
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions =
options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
});
};

await window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true,
null,
{
'test-attribute': 'test-value',
}
);

// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

await window.mParticle.forwarder.selectPlacements({
identifier: 'test-placement',
attributes: {},
});

window.Rokt.selectPlacementsOptions.attributes.should.deepEqual(
{
'test-attribute': 'test-value',
customerid: 'customer123',
email: 'test@example.com',
mpid: '123',
}
);
});

it('should handle case when filteredUser is null', async () => {
Comment thread
rmi22186 marked this conversation as resolved.
Outdated
window.mParticle.Rokt.filters = {
userAttributeFilters: [],
filterUserAttributes: function (attributes) {
return attributes;
},
filteredUser: null,
};

// Set up the createLauncher to properly resolve asynchronously
window.Rokt.createLauncher = async function () {
return Promise.resolve({
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions =
options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
});
};

await window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true,
null,
{
'test-attribute': 'test-value',
}
);

// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

await window.mParticle.forwarder.selectPlacements({
identifier: 'test-placement',
attributes: {},
});

window.Rokt.selectPlacementsOptions.attributes.should.deepEqual(
{
'test-attribute': 'test-value',
mpid: null,
}
);
});

it('should handle case when getUserIdentities function does not exist', async () => {
Comment thread
rmi22186 marked this conversation as resolved.
Outdated
window.mParticle.Rokt.filters = {
userAttributeFilters: [],
filterUserAttributes: function (attributes) {
return attributes;
},
filteredUser: {
getMPID: function () {
return '123';
},
// getUserIdentities is intentionally missing
},
};

window.Rokt.createLauncher = async function () {
return Promise.resolve({
selectPlacements: function (options) {
window.mParticle.Rokt.selectPlacementsOptions =
options;
window.mParticle.Rokt.selectPlacementsCalled = true;
},
});
};

await window.mParticle.forwarder.init(
{
accountId: '123456',
},
reportService.cb,
true,
null,
{
'test-attribute': 'test-value',
}
);

// Wait for initialization to complete (after launcher is created)
await waitForCondition(() => {
return window.mParticle.forwarder.isInitialized;
});

await window.mParticle.forwarder.selectPlacements({
identifier: 'test-placement',
attributes: {},
});

window.Rokt.selectPlacementsOptions.attributes.should.deepEqual(
{
'test-attribute': 'test-value',
mpid: '123',
}
);
});
});
});

describe('#setUserAttribute', () => {
Expand Down