UNPKG

mk9-prebid

Version:

Header Bidding Management Library

1,363 lines (1,204 loc) 104 kB
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' }