mk9-prebid
Version:
Header Bidding Management Library
1,363 lines (1,204 loc) • 104 kB
JavaScript
import {
attachIdSystem,
auctionDelay,
coreStorage,
init,
requestBidsHook,
setStoredConsentData,
setStoredValue,
setSubmoduleRegistry,
syncDelay,
PBJS_USER_ID_OPTOUT_NAME,
findRootDomain,
} from 'modules/userId/index.js';
import {createEidsArray} from 'modules/userId/eids.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
import events from 'src/events.js';
import CONSTANTS from 'src/constants.json';
import {getGlobal} from 'src/prebidGlobal.js';
import {
requestBidsHook as consentManagementRequestBidsHook,
resetConsentData,
setConsentConfig
} from 'modules/consentManagement.js';
import {server} from 'test/mocks/xhr.js';
import find from 'core-js-pure/features/array/find.js';
import {unifiedIdSubmodule} from 'modules/unifiedIdSystem.js';
import {britepoolIdSubmodule} from 'modules/britepoolIdSystem.js';
import {id5IdSubmodule} from 'modules/id5IdSystem.js';
import {identityLinkSubmodule} from 'modules/identityLinkIdSystem.js';
import {dmdIdSubmodule} from 'modules/dmdIdSystem.js';
import {liveIntentIdSubmodule} from 'modules/liveIntentIdSystem.js';
import {merkleIdSubmodule} from 'modules/merkleIdSystem.js';
import {netIdSubmodule} from 'modules/netIdSystem.js';
import {nextrollIdSubmodule} from 'modules/nextrollIdSystem.js';
import {intentIqIdSubmodule} from 'modules/intentIqIdSystem.js';
import {zeotapIdPlusSubmodule} from 'modules/zeotapIdPlusIdSystem.js';
import {sharedIdSystemSubmodule} from 'modules/sharedIdSystem.js';
import {haloIdSubmodule} from 'modules/haloIdSystem.js';
import {pubProvidedIdSubmodule} from 'modules/pubProvidedIdSystem.js';
import {criteoIdSubmodule} from 'modules/criteoIdSystem.js';
import {mwOpenLinkIdSubModule} from 'modules/mwOpenLinkIdSystem.js';
import {tapadIdSubmodule} from 'modules/tapadIdSystem.js';
import {getPrebidInternal} from 'src/utils.js';
import {uid2IdSubmodule} from 'modules/uid2IdSystem.js';
import {admixerIdSubmodule} from 'modules/admixerIdSystem.js';
import {deepintentDpesSubmodule} from 'modules/deepintentDpesIdSystem.js';
import {flocIdSubmodule} from 'modules/flocIdSystem.js'
import {amxIdSubmodule} from '../../../modules/amxIdSystem.js';
import {akamaiDAPIdSubmodule} from 'modules/akamaiDAPIdSystem.js'
import {kinessoIdSubmodule} from 'modules/kinessoIdSystem.js'
let assert = require('chai').assert;
let expect = require('chai').expect;
const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT';
const CONSENT_LOCAL_STORAGE_NAME = '_pbjs_userid_consent_data';
describe('User ID', function () {
function getConfigMock(...configArrays) {
return {
userSync: {
syncDelay: 0,
userIds: configArrays.map(configArray => (configArray && configArray.length >= 3) ? getStorageMock.apply(null, configArray) : null)
}
}
}
function getStorageMock(name = 'pubCommonId', key = 'pubcid', type = 'cookie', expires = 30, refreshInSeconds) {
return {name: name, storage: {name: key, type: type, expires: expires, refreshInSeconds: refreshInSeconds}}
}
function getConfigValueMock(name, value) {
return {
userSync: {syncDelay: 0, userIds: [{name: name, value: value}]}
}
}
function getAdUnitMock(code = 'adUnit-code') {
return {
code,
mediaTypes: {banner: {}, native: {}},
sizes: [[300, 200], [300, 600]],
bids: [{bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}}, {bidder: 'anotherSampleBidder', params: {placementId: 'banner-only-bidder'}}]
};
}
function addConfig(cfg, name, value) {
if (cfg && cfg.userSync && cfg.userSync.userIds) {
cfg.userSync.userIds.forEach(element => {
if (element[name] !== undefined) {
element[name] = Object.assign(element[name], value);
} else {
element[name] = value;
}
});
}
return cfg;
}
function findEid(eids, source) {
return find(eids, (eid) => {
if (eid.source === source) { return true; }
});
}
before(function () {
localStorage.removeItem(PBJS_USER_ID_OPTOUT_NAME);
});
beforeEach(function () {
coreStorage.setCookie(CONSENT_LOCAL_STORAGE_NAME, '', EXPIRED_COOKIE_DATE);
});
describe('Decorate Ad Units', function () {
beforeEach(function () {
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);
coreStorage.setCookie('pubcid_alt', 'altpubcid200000', (new Date(Date.now() + 5000).toUTCString()));
sinon.spy(coreStorage, 'setCookie');
});
afterEach(function () {
$$PREBID_GLOBAL$$.requestBids.removeAll();
config.resetConfig();
coreStorage.setCookie.restore();
});
after(function () {
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);
coreStorage.setCookie('pubcid_alt', '', EXPIRED_COOKIE_DATE);
});
it('Check same cookie behavior', function () {
let adUnits1 = [getAdUnitMock()];
let adUnits2 = [getAdUnitMock()];
let innerAdUnits1;
let innerAdUnits2;
let pubcid = coreStorage.getCookie('pubcid');
expect(pubcid).to.be.null; // there should be no cookie initially
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
requestBidsHook(config => {
innerAdUnits1 = config.adUnits
}, {adUnits: adUnits1});
pubcid = coreStorage.getCookie('pubcid'); // cookies is created after requestbidHook
innerAdUnits1.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal(pubcid);
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: pubcid, atype: 1}]
});
});
});
requestBidsHook(config => {
innerAdUnits2 = config.adUnits
}, {adUnits: adUnits2});
assert.deepEqual(innerAdUnits1, innerAdUnits2);
});
it('Check different cookies', function () {
let adUnits1 = [getAdUnitMock()];
let adUnits2 = [getAdUnitMock()];
let innerAdUnits1;
let innerAdUnits2;
let pubcid1;
let pubcid2;
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
requestBidsHook((config) => {
innerAdUnits1 = config.adUnits
}, {adUnits: adUnits1});
pubcid1 = coreStorage.getCookie('pubcid'); // get first cookie
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); // erase cookie
innerAdUnits1.forEach((unit) => {
unit.bids.forEach((bid) => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal(pubcid1);
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: pubcid1, atype: 1}]
});
});
});
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
requestBidsHook((config) => {
innerAdUnits2 = config.adUnits
}, {adUnits: adUnits2});
pubcid2 = coreStorage.getCookie('pubcid'); // get second cookie
innerAdUnits2.forEach((unit) => {
unit.bids.forEach((bid) => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal(pubcid2);
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: pubcid2, atype: 1}]
});
});
});
expect(pubcid1).to.not.equal(pubcid2);
});
it('Use existing cookie', function () {
let adUnits = [getAdUnitMock()];
let innerAdUnits;
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid_alt', 'cookie']));
requestBidsHook((config) => {
innerAdUnits = config.adUnits
}, {adUnits});
innerAdUnits.forEach((unit) => {
unit.bids.forEach((bid) => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('altpubcid200000');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: 'altpubcid200000', atype: 1}]
});
});
});
// Because the consent cookie doesn't exist yet, we'll have two setCookie calls:
// 1) for the consent cookie
// 2) from the getId() call that results in a new call to store the results
expect(coreStorage.setCookie.callCount).to.equal(2);
});
it('Extend cookie', function () {
let adUnits = [getAdUnitMock()];
let innerAdUnits;
let customConfig = getConfigMock(['pubCommonId', 'pubcid_alt', 'cookie']);
customConfig = addConfig(customConfig, 'params', {extend: true});
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule]);
init(config);
config.setConfig(customConfig);
requestBidsHook((config) => {
innerAdUnits = config.adUnits
}, {adUnits});
innerAdUnits.forEach((unit) => {
unit.bids.forEach((bid) => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('altpubcid200000');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: 'altpubcid200000', atype: 1}]
});
});
});
// Because extend is true, the cookie will be updated even if it exists already. The second setCookie call
// is for storing consentData
expect(coreStorage.setCookie.callCount).to.equal(2);
});
it('Disable auto create', function () {
let adUnits = [getAdUnitMock()];
let innerAdUnits;
let customConfig = getConfigMock(['pubCommonId', 'pubcid', 'cookie']);
customConfig = addConfig(customConfig, 'params', {create: false});
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule]);
init(config);
config.setConfig(customConfig);
requestBidsHook((config) => {
innerAdUnits = config.adUnits
}, {adUnits});
innerAdUnits.forEach((unit) => {
unit.bids.forEach((bid) => {
expect(bid).to.not.have.deep.nested.property('userId.pubcid');
expect(bid).to.not.have.deep.nested.property('userIdAsEids');
});
});
// setCookie is called once in order to store consentData
expect(coreStorage.setCookie.callCount).to.equal(1);
});
it('pbjs.getUserIds', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'pubCommonId', value: {'pubcid': '11111'}
}]
}
});
expect(typeof (getGlobal()).getUserIds).to.equal('function');
expect((getGlobal()).getUserIds()).to.deep.equal({pubcid: '11111'});
});
it('pbjs.getUserIdsAsEids', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'pubCommonId', value: {'pubcid': '11111'}
}]
}
});
expect(typeof (getGlobal()).getUserIdsAsEids).to.equal('function');
expect((getGlobal()).getUserIdsAsEids()).to.deep.equal(createEidsArray((getGlobal()).getUserIds()));
});
it('pbjs.refreshUserIds refreshes', function() {
let sandbox = sinon.createSandbox();
let mockIdCallback = sandbox.stub().returns({id: {'MOCKID': '1111'}});
let mockIdSystem = {
name: 'mockId',
decode: function(value) {
return {
'mid': value['MOCKID']
};
},
getId: mockIdCallback
};
setSubmoduleRegistry([mockIdSystem]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'mockId',
value: {id: {mockId: '1111'}}
}]
}
});
expect(typeof (getGlobal()).refreshUserIds).to.equal('function');
getGlobal().getUserIds(); // force initialization
// update config so that getId will be called
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'mockId',
storage: {name: 'mockid', type: 'cookie'},
}]
}
});
getGlobal().refreshUserIds();
expect(mockIdCallback.callCount).to.equal(1);
});
it('pbjs.refreshUserIds updates submodules', function() {
let sandbox = sinon.createSandbox();
let mockIdCallback = sandbox.stub().returns({id: {'MOCKID': '1111'}});
let mockIdSystem = {
name: 'mockId',
decode: function(value) {
return {
'mid': value['MOCKID']
};
},
getId: mockIdCallback
};
setSubmoduleRegistry([mockIdSystem]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'mockId',
value: {id: {mockId: '1111'}}
}]
}
});
expect(getGlobal().getUserIds().id.mockId).to.equal('1111');
// update to new config value
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'mockId',
value: {id: {mockId: '1212'}}
}]
}
});
getGlobal().refreshUserIds({ submoduleNames: ['mockId'] });
expect(getGlobal().getUserIds().id.mockId).to.equal('1212');
});
it('pbjs.refreshUserIds refreshes single', function() {
coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE);
coreStorage.setCookie('REFRESH', '', EXPIRED_COOKIE_DATE);
let sandbox = sinon.createSandbox();
let mockIdCallback = sandbox.stub().returns({id: {'MOCKID': '1111'}});
let refreshUserIdsCallback = sandbox.stub();
let mockIdSystem = {
name: 'mockId',
decode: function(value) {
return {
'mid': value['MOCKID']
};
},
getId: mockIdCallback
};
let refreshedIdCallback = sandbox.stub().returns({id: {'REFRESH': '1111'}});
let refreshedIdSystem = {
name: 'refreshedId',
decode: function(value) {
return {
'refresh': value['REFRESH']
};
},
getId: refreshedIdCallback
};
setSubmoduleRegistry([refreshedIdSystem, mockIdSystem]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [
{
name: 'mockId',
storage: {name: 'MOCKID', type: 'cookie'},
},
{
name: 'refreshedId',
storage: {name: 'refreshedid', type: 'cookie'},
}
]
}
});
getGlobal().getUserIds(); // force initialization
getGlobal().refreshUserIds({submoduleNames: 'refreshedId'}, refreshUserIdsCallback);
expect(refreshedIdCallback.callCount).to.equal(2);
expect(mockIdCallback.callCount).to.equal(1);
expect(refreshUserIdsCallback.callCount).to.equal(1);
});
});
describe('Opt out', function () {
before(function () {
coreStorage.setCookie(PBJS_USER_ID_OPTOUT_NAME, '1', (new Date(Date.now() + 5000).toUTCString()));
});
beforeEach(function () {
sinon.stub(utils, 'logInfo');
});
afterEach(function () {
// removed cookie
coreStorage.setCookie(PBJS_USER_ID_OPTOUT_NAME, '', EXPIRED_COOKIE_DATE);
$$PREBID_GLOBAL$$.requestBids.removeAll();
utils.logInfo.restore();
config.resetConfig();
});
it('fails initialization if opt out cookie exists', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
expect(utils.logInfo.args[0][0]).to.exist.and.to.equal('User ID - opt-out cookie found, exit module');
});
it('initializes if no opt out cookie exists', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 1 submodules');
});
});
describe('Handle variations of config values', function () {
beforeEach(function () {
sinon.stub(utils, 'logInfo');
});
afterEach(function () {
$$PREBID_GLOBAL$$.requestBids.removeAll();
utils.logInfo.restore();
config.resetConfig();
});
it('handles config with no usersync object', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({});
// usersync is undefined, and no logInfo message for 'User ID - usersync config updated'
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});
it('handles config with empty usersync object', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({userSync: {}});
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});
it('handles config with usersync and userIds that are empty objs', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
userIds: [{}]
}
});
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});
it('handles config with usersync and userIds with empty names or that dont match a submodule.name', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
userIds: [{
name: '',
value: {test: '1'}
}, {
name: 'foo',
value: {test: '1'}
}]
}
});
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});
it('config with 1 configurations should create 1 submodules', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['unifiedId', 'unifiedid', 'cookie']));
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 1 submodules');
});
it('handles config with name in different case', function () {
setSubmoduleRegistry([criteoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
userIds: [{
name: 'Criteo'
}]
}
});
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 1 submodules');
});
it('config with 23 configurations should result in 23 submodules add', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'pubProvidedId'
}, {
name: 'pubCommonId', value: {'pubcid': '11111'}
}, {
name: 'unifiedId',
storage: {name: 'unifiedid', type: 'cookie'}
}, {
name: 'id5Id',
storage: {name: 'id5id', type: 'cookie'}
}, {
name: 'identityLink',
storage: {name: 'idl_env', type: 'cookie'}
}, {
name: 'liveIntentId',
storage: {name: '_li_pbid', type: 'cookie'}
}, {
name: 'britepoolId',
value: {'primaryBPID': '279c0161-5152-487f-809e-05d7f7e653fd'}
}, {
name: 'netId',
storage: {name: 'netId', type: 'cookie'}
}, {
name: 'nextrollId'
}, {
name: 'intentIqId',
storage: {name: 'intentIqId', type: 'cookie'}
}, {
name: 'haloId',
storage: {name: 'haloId', type: 'cookie'}
}, {
name: 'zeotapIdPlus'
}, {
name: 'criteo'
}, {
name: 'mwOpenLinkId'
}, {
name: 'tapadId',
storage: {name: 'tapad_id', type: 'cookie'}
}, {
name: 'uid2'
}, {
name: 'admixerId',
storage: {name: 'admixerId', type: 'cookie'}
}, {
name: 'deepintentId',
storage: {name: 'deepintentId', type: 'cookie'}
}, {
name: 'flocId'
}, {
name: 'akamaiDAPId'
}, {
name: 'dmdId',
storage: {name: 'dmdId', type: 'cookie'}
}, {
name: 'amxId',
storage: {name: 'amxId', type: 'html5'}
}, {
name: 'kpuid',
storage: {name: 'kpuid', type: 'cookie'}
}]
}
});
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 23 submodules');
});
it('config syncDelay updates module correctly', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
syncDelay: 99,
userIds: [{
name: 'unifiedId',
storage: {name: 'unifiedid', type: 'cookie'}
}]
}
});
expect(syncDelay).to.equal(99);
});
it('config auctionDelay updates module correctly', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
auctionDelay: 100,
userIds: [{
name: 'unifiedId',
storage: {name: 'unifiedid', type: 'cookie'}
}]
}
});
expect(auctionDelay).to.equal(100);
});
it('config auctionDelay defaults to 0 if not a number', function () {
setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]);
init(config);
config.setConfig({
userSync: {
auctionDelay: '',
userIds: [{
name: 'unifiedId',
storage: {name: 'unifiedid', type: 'cookie'}
}]
}
});
expect(auctionDelay).to.equal(0);
});
describe('auction and user sync delays', function () {
let sandbox;
let adUnits;
let mockIdCallback;
let auctionSpy;
beforeEach(function () {
sandbox = sinon.createSandbox();
sandbox.stub(global, 'setTimeout').returns(2);
sandbox.stub(global, 'clearTimeout');
sandbox.stub(events, 'on');
sandbox.stub(coreStorage, 'getCookie');
// remove cookie
coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE);
adUnits = [getAdUnitMock()];
auctionSpy = sandbox.spy();
mockIdCallback = sandbox.stub();
const mockIdSystem = {
name: 'mockId',
decode: function (value) {
return {
'mid': value['MOCKID']
};
},
getId: function () {
const storedId = coreStorage.getCookie('MOCKID');
if (storedId) {
return {id: {'MOCKID': storedId}};
}
return {callback: mockIdCallback};
}
};
init(config);
attachIdSystem(mockIdSystem, true);
});
afterEach(function () {
$$PREBID_GLOBAL$$.requestBids.removeAll();
config.resetConfig();
sandbox.restore();
});
it('delays auction if auctionDelay is set, timing out at auction delay', function () {
config.setConfig({
userSync: {
auctionDelay: 33,
syncDelay: 77,
userIds: [{
name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'}
}]
}
});
requestBidsHook(auctionSpy, {adUnits});
// check auction was delayed
global.clearTimeout.calledOnce.should.equal(false);
global.setTimeout.calledOnce.should.equal(true);
global.setTimeout.calledWith(sinon.match.func, 33);
auctionSpy.calledOnce.should.equal(false);
// check ids were fetched
mockIdCallback.calledOnce.should.equal(true);
// callback to continue auction if timed out
global.setTimeout.callArg(0);
auctionSpy.calledOnce.should.equal(true);
// does not call auction again once ids are synced
mockIdCallback.callArgWith(0, {'MOCKID': '1234'});
auctionSpy.calledOnce.should.equal(true);
// no sync after auction ends
events.on.called.should.equal(false);
});
it('delays auction if auctionDelay is set, continuing auction if ids are fetched before timing out', function (done) {
config.setConfig({
userSync: {
auctionDelay: 33,
syncDelay: 77,
userIds: [{
name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'}
}]
}
});
requestBidsHook(auctionSpy, {adUnits});
// check auction was delayed
// global.setTimeout.calledOnce.should.equal(true);
global.clearTimeout.calledOnce.should.equal(false);
global.setTimeout.calledWith(sinon.match.func, 33);
auctionSpy.calledOnce.should.equal(false);
// check ids were fetched
mockIdCallback.calledOnce.should.equal(true);
// if ids returned, should continue auction
mockIdCallback.callArgWith(0, {'MOCKID': '1234'});
auctionSpy.calledOnce.should.equal(true);
// check ids were copied to bids
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.mid');
expect(bid.userId.mid).to.equal('1234');
expect(bid.userIdAsEids.length).to.equal(0);// "mid" is an un-known submodule for USER_IDS_CONFIG in eids.js
});
done();
});
// no sync after auction ends
events.on.called.should.equal(false);
});
it('does not delay auction if not set, delays id fetch after auction ends with syncDelay', function () {
config.setConfig({
userSync: {
syncDelay: 77,
userIds: [{
name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'}
}]
}
});
// check config has been set correctly
expect(auctionDelay).to.equal(0);
expect(syncDelay).to.equal(77);
requestBidsHook(auctionSpy, {adUnits});
// should not delay auction
global.setTimeout.calledOnce.should.equal(false);
auctionSpy.calledOnce.should.equal(true);
// check user sync is delayed after auction is ended
mockIdCallback.calledOnce.should.equal(false);
events.on.calledOnce.should.equal(true);
events.on.calledWith(CONSTANTS.EVENTS.AUCTION_END, sinon.match.func);
// once auction is ended, sync user ids after delay
events.on.callArg(1);
global.setTimeout.calledOnce.should.equal(true);
global.setTimeout.calledWith(sinon.match.func, 77);
mockIdCallback.calledOnce.should.equal(false);
// once sync delay is over, ids should be fetched
global.setTimeout.callArg(0);
mockIdCallback.calledOnce.should.equal(true);
});
it('does not delay user id sync after auction ends if set to 0', function () {
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'}
}]
}
});
expect(syncDelay).to.equal(0);
requestBidsHook(auctionSpy, {adUnits});
// auction should not be delayed
global.setTimeout.calledOnce.should.equal(false);
auctionSpy.calledOnce.should.equal(true);
// sync delay after auction is ended
mockIdCallback.calledOnce.should.equal(false);
events.on.calledOnce.should.equal(true);
events.on.calledWith(CONSTANTS.EVENTS.AUCTION_END, sinon.match.func);
// once auction is ended, if no sync delay, fetch ids
events.on.callArg(1);
global.setTimeout.calledOnce.should.equal(false);
mockIdCallback.calledOnce.should.equal(true);
});
it('does not delay auction if there are no ids to fetch', function () {
coreStorage.getCookie.withArgs('MOCKID').returns('123456778');
config.setConfig({
userSync: {
auctionDelay: 33,
syncDelay: 77,
userIds: [{
name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'}
}]
}
});
requestBidsHook(auctionSpy, {adUnits});
global.setTimeout.calledOnce.should.equal(false);
auctionSpy.calledOnce.should.equal(true);
mockIdCallback.calledOnce.should.equal(false);
// no sync after auction ends
events.on.called.should.equal(false);
});
});
describe('Request bids hook appends userId to bid objs in adapters', function () {
let adUnits;
beforeEach(function () {
adUnits = [getAdUnitMock()];
});
it('test hook from pubcommonid cookie', function (done) {
coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 100000).toUTCString()));
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('testpubcid');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: 'testpubcid', atype: 1}]
});
});
});
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from pubcommonid html5', function (done) {
// simulate existing browser local storage values
localStorage.setItem('pubcid', 'testpubcid');
localStorage.setItem('pubcid_exp', new Date(Date.now() + 100000).toUTCString());
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'html5']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('testpubcid');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [{id: 'testpubcid', atype: 1}]
});
});
});
localStorage.removeItem('pubcid');
localStorage.removeItem('pubcid_exp');
done();
}, {adUnits});
});
it('test hook from pubcommonid config value object', function (done) {
setSubmoduleRegistry([sharedIdSystemSubmodule]);
init(config);
config.setConfig(getConfigValueMock('pubCommonId', {'pubcidvalue': 'testpubcidvalue'}));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.pubcidvalue');
expect(bid.userId.pubcidvalue).to.equal('testpubcidvalue');
expect(bid.userIdAsEids.length).to.equal(0);// "pubcidvalue" is an un-known submodule for USER_IDS_CONFIG in eids.js
});
});
done();
}, {adUnits});
});
it('test hook from UnifiedId html5', function (done) {
// simulate existing browser local storage values
localStorage.setItem('unifiedid_alt', JSON.stringify({'TDID': 'testunifiedid_alt'}));
localStorage.setItem('unifiedid_alt_exp', '');
setSubmoduleRegistry([unifiedIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['unifiedId', 'unifiedid_alt', 'html5']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.tdid');
expect(bid.userId.tdid).to.equal('testunifiedid_alt');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'adserver.org',
uids: [{id: 'testunifiedid_alt', atype: 1, ext: {rtiPartner: 'TDID'}}]
});
});
});
localStorage.removeItem('unifiedid_alt');
localStorage.removeItem('unifiedid_alt_exp');
done();
}, {adUnits});
});
it('test hook from amxId html5', (done) => {
// simulate existing localStorage values
localStorage.setItem('amxId', 'test_amxid_id');
localStorage.setItem('amxId_exp', '');
setSubmoduleRegistry([amxIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['amxId', 'amxId', 'html5']));
requestBidsHook(() => {
adUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
expect(bid).to.have.deep.nested.property('userId.amxId');
expect(bid.userId.amxId).to.equal('test_amxid_id');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'amxrtb.com',
uids: [{
id: 'test_amxid_id',
atype: 1,
}]
});
});
});
// clear LS
localStorage.removeItem('amxId');
localStorage.removeItem('amxId_exp');
done();
}, {adUnits});
});
it('test hook from identityLink html5', function (done) {
// simulate existing browser local storage values
localStorage.setItem('idl_env', 'AiGNC8Z5ONyZKSpIPf');
localStorage.setItem('idl_env_exp', '');
setSubmoduleRegistry([identityLinkSubmodule]);
init(config);
config.setConfig(getConfigMock(['identityLink', 'idl_env', 'html5']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.idl_env');
expect(bid.userId.idl_env).to.equal('AiGNC8Z5ONyZKSpIPf');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'liveramp.com',
uids: [{id: 'AiGNC8Z5ONyZKSpIPf', atype: 3}]
});
});
});
localStorage.removeItem('idl_env');
localStorage.removeItem('idl_env_exp');
done();
}, {adUnits});
});
it('test hook from identityLink cookie', function (done) {
coreStorage.setCookie('idl_env', 'AiGNC8Z5ONyZKSpIPf', (new Date(Date.now() + 100000).toUTCString()));
setSubmoduleRegistry([identityLinkSubmodule]);
init(config);
config.setConfig(getConfigMock(['identityLink', 'idl_env', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.idl_env');
expect(bid.userId.idl_env).to.equal('AiGNC8Z5ONyZKSpIPf');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'liveramp.com',
uids: [{id: 'AiGNC8Z5ONyZKSpIPf', atype: 3}]
});
});
});
coreStorage.setCookie('idl_env', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from criteoIdModule cookie', function (done) {
coreStorage.setCookie('storage_bidid', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 100000).toUTCString()));
setSubmoduleRegistry([criteoIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['criteo', 'storage_bidid', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.criteoId');
expect(bid.userId.criteoId).to.equal('test_bidid');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'criteo.com',
uids: [{id: 'test_bidid', atype: 1}]
});
});
});
coreStorage.setCookie('storage_bidid', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from tapadIdModule cookie', function (done) {
coreStorage.setCookie('tapad_id', 'test-tapad-id', (new Date(Date.now() + 100000).toUTCString()));
setSubmoduleRegistry([tapadIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['tapadId', 'tapad_id', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.tapadId');
expect(bid.userId.tapadId).to.equal('test-tapad-id');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'tapad.com',
uids: [{id: 'test-tapad-id', atype: 1}]
});
});
})
coreStorage.setCookie('tapad_id', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from liveIntentId html5', function (done) {
// simulate existing browser local storage values
localStorage.setItem('_li_pbid', JSON.stringify({'unifiedId': 'random-ls-identifier'}));
localStorage.setItem('_li_pbid_exp', '');
setSubmoduleRegistry([liveIntentIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'html5']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.lipb');
expect(bid.userId.lipb.lipbid).to.equal('random-ls-identifier');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'liveintent.com',
uids: [{id: 'random-ls-identifier', atype: 3}]
});
});
});
localStorage.removeItem('_li_pbid');
localStorage.removeItem('_li_pbid_exp');
done();
}, {adUnits});
});
it('test hook from Kinesso cookies', function (done) {
// simulate existing browser local storage values
coreStorage.setCookie('kpuid', 'KINESSO_ID', (new Date(Date.now() + 5000).toUTCString()));
setSubmoduleRegistry([kinessoIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['kpuid', 'kpuid', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.kpuid');
expect(bid.userId.kpuid).to.equal('KINESSO_ID');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'kpuid.com',
uids: [{id: 'KINESSO_ID', atype: 3}]
});
});
});
coreStorage.setCookie('kpuid', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from Kinesso html5', function (done) {
// simulate existing browser local storage values
localStorage.setItem('kpuid', 'KINESSO_ID');
localStorage.setItem('kpuid_exp', '');
setSubmoduleRegistry([kinessoIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['kpuid', 'kpuid', 'html5']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.kpuid');
expect(bid.userId.kpuid).to.equal('KINESSO_ID');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'kpuid.com',
uids: [{id: 'KINESSO_ID', atype: 3}]
});
});
});
localStorage.removeItem('kpuid');
localStorage.removeItem('kpuid_exp', '');
done();
}, {adUnits});
});
it('test hook from liveIntentId cookie', function (done) {
coreStorage.setCookie('_li_pbid', JSON.stringify({'unifiedId': 'random-cookie-identifier'}), (new Date(Date.now() + 100000).toUTCString()));
setSubmoduleRegistry([liveIntentIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'cookie']));
requestBidsHook(function () {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.lipb');
expect(bid.userId.lipb.lipbid).to.equal('random-cookie-identifier');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'liveintent.com',
uids: [{id: 'random-cookie-identifier', atype: 3}]
});
});
});
coreStorage.setCookie('_li_pbid', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('eidPermissions fun with bidders', function (done) {
coreStorage.setCookie('pubcid', 'test222', (new Date(Date.now() + 5000).toUTCString()));
setSubmoduleRegistry([sharedIdSystemSubmodule]);
let eidPermissions;
getPrebidInternal().setEidPermissions = function (newEidPermissions) {
eidPermissions = newEidPermissions;
}
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [
{
name: 'pubCommonId',
bidders: [
'sampleBidder'
],
storage: {
type: 'cookie',
name: 'pubcid',
expires: 28
}
}
]
}
});
requestBidsHook(function () {
expect(eidPermissions).to.deep.equal(
[
{
bidders: [
'sampleBidder'
],
source: 'pubcid.org'
}
]
);
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
if (bid.bidder === 'sampleBidder') {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('test222');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [
{
id: 'test222',
atype: 1
}
]
});
}
if (bid.bidder === 'anotherSampleBidder') {
expect(bid).to.not.have.deep.nested.property('userId.pubcid');
expect(bid).to.not.have.property('userIdAsEids');
}
});
});
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);
getPrebidInternal().setEidPermissions = undefined;
done();
}, {adUnits});
});
it('eidPermissions fun without bidders', function (done) {
coreStorage.setCookie('pubcid', 'test222', new Date(Date.now() + 5000).toUTCString());
setSubmoduleRegistry([sharedIdSystemSubmodule]);
let eidPermissions;
getPrebidInternal().setEidPermissions = function (newEidPermissions) {
eidPermissions = newEidPermissions;
}
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [
{
name: 'pubCommonId',
storage: {
type: 'cookie',
name: 'pubcid',
expires: 28
}
}
]
}
});
requestBidsHook(function () {
expect(eidPermissions).to.deep.equal(
[]
);
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.pubcid');
expect(bid.userId.pubcid).to.equal('test222');
expect(bid.userIdAsEids[0]).to.deep.equal({
source: 'pubcid.org',
uids: [
{
id: 'test222',
atype: 1
}]
});
});
});
getPrebidInternal().setEidPermissions = undefined;
coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);
done();
}, {adUnits});
});
it('test hook from pubProvidedId config params', function (done) {
setSubmoduleRegistry([pubProvidedIdSubmodule]);
init(config);
config.setConfig({
userSync: {
syncDelay: 0,
userIds: [{
name: 'pubProvidedId',
params: {
eids: [{
source: 'example.com',
uids: [{
id: 'value read from cookie or local storage',
ext: {
stype: 'ppuid'
}
}]
}, {
source: 'id-partner.com',
uids: [{
id: 'value read from cookie or local storage',
ext: {
stype: 'dmp'
}