Skip to content
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

Zeotap ID+ submodule #5640

Merged
merged 10 commits into from
Sep 11, 2020
3 changes: 3 additions & 0 deletions integrationExamples/gpt/userId_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@
name: "_li_pbid",
expires: 28
}
},
{
name: "zeotapIdPlus"
}],
syncDelay: 5000,
auctionDelay: 1000
Expand Down
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"netIdSystem",
"identityLinkIdSystem",
"sharedIdSystem",
"intentIqIdSystem"
"intentIqIdSystem",
"zeotapIdPlusIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
5 changes: 5 additions & 0 deletions modules/userId/eids.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ const USER_IDS_CONFIG = {
third: data.third
} : undefined;
}
},
// zeotapIdPlus
'IDP': {
source: 'zeotap.com',
atype: 1
}
};

Expand Down
9 changes: 8 additions & 1 deletion modules/userId/eids.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ userIdAsEids = [
third: 'some-random-id-value'
}
}]
}
},
{
source: 'zeotap.com',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
},
]
```
52 changes: 52 additions & 0 deletions modules/zeotapIdPlusIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* This module adds Zeotap to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/zeotapIdPlusIdSystem
* @requires module:modules/userId
*/
import * as utils from '../src/utils.js'
import {submodule} from '../src/hook.js';
import { getStorageManager } from '../src/storageManager.js';

const ZEOTAP_COOKIE_NAME = 'IDP';
Copy link
Collaborator

Choose a reason for hiding this comment

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

should this be configurable by the pub? can you read if this is set in config and fallback to 'IDP' ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@patmmccann I have added the tests to eid spec file. The cookie name 'IDP' is not configurable by the pub. It gets added to the storage by Zeotap JS after publisher integration. I didn't get the other question.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks!

const storage = getStorageManager();

function readCookie() {
return storage.cookiesAreEnabled ? storage.getCookie(ZEOTAP_COOKIE_NAME) : null;
}

function readFromLocalStorage() {
return storage.localStorageIsEnabled ? storage.getDataFromLocalStorage(ZEOTAP_COOKIE_NAME) : null;
}

/** @type {Submodule} */
export const zeotapIdPlusSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: 'zeotapIdPlus',
/**
* decode the stored id value for passing to bid requests
* @function
* @param { Object | string | undefined } value
* @return { Object | string | undefined }
*/
decode(value) {
const id = value ? utils.isStr(value) ? value : utils.isPlainObject(value) ? value.id : undefined : undefined;
return id ? {
'IDP': JSON.parse(atob(id))
} : undefined;
},
/**
* performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleParams} configParams
* @return {{id: string | undefined} | undefined}
*/
getId() {
const id = readCookie() || readFromLocalStorage();
return id ? { id } : undefined;
}
};
submodule('userId', zeotapIdPlusSubmodule);
14 changes: 14 additions & 0 deletions test/spec/modules/eids_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,20 @@ describe('eids array generation for known sub-modules', function() {
}]
});
});
it('zeotapIdPlus', function() {
const userId = {
IDP: 'some-random-id-value'
};
const newEids = createEidsArray(userId);
expect(newEids.length).to.equal(1);
expect(newEids[0]).to.deep.equal({
source: 'zeotap.com',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
});
});
});

describe('Negative case', function() {
Expand Down
87 changes: 67 additions & 20 deletions test/spec/modules/userId_spec.js

Large diffs are not rendered by default.

141 changes: 141 additions & 0 deletions test/spec/modules/zeotapIdPlusIdSystem_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { expect } from 'chai';
import find from 'core-js-pure/features/array/find.js';
import { config } from 'src/config.js';
import { newStorageManager } from 'src/storageManager.js';
import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js';
import { zeotapIdPlusSubmodule } from 'modules/zeotapIdPlusIdSystem.js';

const storage = newStorageManager();

const ZEOTAP_COOKIE_NAME = 'IDP';
const ZEOTAP_COOKIE = 'THIS-IS-A-DUMMY-COOKIE';
const ENCODED_ZEOTAP_COOKIE = btoa(JSON.stringify(ZEOTAP_COOKIE));

function getConfigMock() {
return {
userSync: {
syncDelay: 0,
userIds: [{
name: 'zeotapIdPlus'
}]
}
}
}

function getAdUnitMock(code = 'adUnit-code') {
return {
code,
mediaTypes: {banner: {}, native: {}},
sizes: [
[300, 200],
[300, 600]
],
bids: [{
bidder: 'sampleBidder',
params: { placementId: 'banner-only-bidder' }
}]
};
}

function unsetCookie() {
storage.setCookie(ZEOTAP_COOKIE_NAME, '');
}

function unsetLocalStorage() {
storage.setDataInLocalStorage(ZEOTAP_COOKIE_NAME, '');
}

describe('Zeotap ID System', function() {
describe('test method: getId', function() {
afterEach(() => {
unsetCookie();
unsetLocalStorage();
})

it('provides the stored Zeotap id if a cookie exists', function() {
storage.setCookie(
ZEOTAP_COOKIE_NAME,
ENCODED_ZEOTAP_COOKIE,
(new Date(Date.now() + 5000).toUTCString()),
);
let id = zeotapIdPlusSubmodule.getId();
expect(id).to.deep.equal({
id: ENCODED_ZEOTAP_COOKIE
});
});

it('provides the stored Zeotap id if cookie is absent but present in local storage', function() {
smenzer marked this conversation as resolved.
Show resolved Hide resolved
storage.setDataInLocalStorage(ZEOTAP_COOKIE_NAME, ENCODED_ZEOTAP_COOKIE);
let id = zeotapIdPlusSubmodule.getId();
expect(id).to.deep.equal({
id: ENCODED_ZEOTAP_COOKIE
});
});

it('returns undefined if both cookie and local storage are empty', function() {
let id = zeotapIdPlusSubmodule.getId();
expect(id).to.be.undefined
})
});

describe('test method: decode', function() {
it('provides the Zeotap ID (IDP) from a stored object', function() {
let zeotapId = {
id: ENCODED_ZEOTAP_COOKIE,
};

expect(zeotapIdPlusSubmodule.decode(zeotapId)).to.deep.equal({
IDP: ZEOTAP_COOKIE
});
});

it('provides the Zeotap ID (IDP) from a stored string', function() {
let zeotapId = ENCODED_ZEOTAP_COOKIE;

expect(zeotapIdPlusSubmodule.decode(zeotapId)).to.deep.equal({
IDP: ZEOTAP_COOKIE
});
});
});

describe('requestBids hook', function() {
let adUnits;

beforeEach(function() {
adUnits = [getAdUnitMock()];
storage.setCookie(
ZEOTAP_COOKIE_NAME,
ENCODED_ZEOTAP_COOKIE,
(new Date(Date.now() + 5000).toUTCString()),
);
setSubmoduleRegistry([zeotapIdPlusSubmodule]);
init(config);
config.setConfig(getConfigMock());
});

afterEach(function() {
unsetCookie();
unsetLocalStorage();
});

it('when a stored Zeotap ID exists it is added to bids', function(done) {
requestBidsHook(function() {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.IDP');
expect(bid.userId.IDP).to.equal(ZEOTAP_COOKIE);
const zeotapIdAsEid = find(bid.userIdAsEids, e => e.source == 'zeotap.com');
expect(zeotapIdAsEid).to.deep.equal({
source: 'zeotap.com',
uids: [{
id: ZEOTAP_COOKIE,
atype: 1,
}]
});
});
});
done();
}, { adUnits });
});
});
});