diff --git a/modules/.submodules.json b/modules/.submodules.json index d622ebe96d1..f71325d38a9 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -24,7 +24,8 @@ "mwOpenLinkIdSystem", "tapadIdSystem", "novatiqIdSystem", - "uid2IdSystem" + "uid2IdSystem", + "admixerIdSystem" ], "adpod": [ "freeWheelAdserverVideo", diff --git a/modules/admixerIdSystem.js b/modules/admixerIdSystem.js new file mode 100644 index 00000000000..c963f1e5b88 --- /dev/null +++ b/modules/admixerIdSystem.js @@ -0,0 +1,92 @@ +/** + * This module adds AdmixerId to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/admixerIdSubmodule + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import {getStorageManager} from '../src/storageManager.js'; + +export const storage = getStorageManager(); + +/** @type {Submodule} */ +export const admixerIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'admixerId', + /** + * used to specify vendor id + * @type {number} + */ + gvlid: 511, + /** + * decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{admixerId:string}} + */ + decode(value) { + return { 'admixerId': value } + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleConfig} [config] + * @param {ConsentData} [consentData] + * @returns {IdResponse|undefined} + */ + getId(config, consentData) { + const {e, p, pid} = (config && config.params) || {}; + if (!pid || typeof pid !== 'string') { + utils.logError('admixerId submodule requires partner id to be defined'); + return; + } + const gdpr = (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) ? 1 : 0; + const consentString = gdpr ? consentData.consentString : ''; + if (gdpr && !consentString) { + utils.logInfo('Consent string is required to call admixer id.'); + return; + } + const url = `https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}${e ? `&e=${e}` : ''}${p ? `&p=${p}` : ''}${consentString ? `&cs=${consentString}` : ''}`; + const resp = function(callback) { + if (window.admixTMLoad && window.admixTMLoad.push) { + window.admixTMLoad.push(function() { + window.admixTM.retrieveVisitorId(function(visitorId) { + if (visitorId) { + callback(visitorId); + } else { + callback(); + } + }); + }); + } else { + retrieveVisitorId(url, callback); + } + }; + + return { callback: resp }; + } +}; +function retrieveVisitorId(url, callback) { + ajax(url, { + success: response => { + const {setData: {visitorid} = {}} = JSON.parse(response || '{}'); + if (visitorid) { + callback(visitorid); + } else { + callback(); + } + }, + error: error => { + utils.logInfo(`admixerId: fetch encountered an error`, error); + callback(); + } + }, undefined, { method: 'GET', withCredentials: true }); +} + +submodule('userId', admixerIdSubmodule); diff --git a/modules/userId/eids.js b/modules/userId/eids.js index 465788864b1..a38417683ba 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -206,6 +206,12 @@ const USER_IDS_CONFIG = { getValue: function(data) { return data.id; } + }, + + // Admixer Id + 'admixerId': { + source: 'admixer.net', + atype: 3 } }; diff --git a/modules/userId/eids.md b/modules/userId/eids.md index 89e696b47a1..93783a2db4d 100644 --- a/modules/userId/eids.md +++ b/modules/userId/eids.md @@ -171,12 +171,19 @@ userIdAsEids = [ atype: 1 }] }, - { + { source: 'uidapi.com', uids: [{ id: 'some-random-id-value', atype: 3 }] - } + }, + { + source: 'admixer.net', + uids: [{ + id: 'some-random-id-value', + atype: 3 + }] + } ] ``` diff --git a/modules/userId/userId.md b/modules/userId/userId.md index d5d3d53f6d1..aa72146c47c 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -100,6 +100,18 @@ pbjs.setConfig({ },{ name: 'uid2' } + }, { + name: 'admixerId', + params: { + pid: "4D393FAC-B6BB-4E19-8396-0A4813607316", // example id + e: "3d400b57e069c993babea0bd9efa79e5dc698e16c042686569faae20391fd7ea", // example hashed email (sha256) + p: "05de6c07eb3ea4bce45adca4e0182e771d80fbb99e12401416ca84ddf94c3eb9" //example hashed phone (sha256) + }, + storage: { + type: 'cookie', + name: '__adm__admixer', + expires: 30 + } }], syncDelay: 5000, auctionDelay: 1000 @@ -171,18 +183,18 @@ pbjs.setConfig({ expires: 90, // Expiration in days refreshInSeconds: 8*3600 // User Id cache lifetime in seconds, defaulting to 'expires' }, - }, { - name: 'nextrollId', - params: { - partnerId: "1009", // Set your real NextRoll partner ID here for production - } - }, { + }, { + name: 'nextrollId', + params: { + partnerId: "1009", // Set your real NextRoll partner ID here for production + } + }, { name: 'criteo', storage: { // It is best not to specify this parameter since the module needs to be called as many times as possible type: 'html5', name: '_criteoId', expires: 1 - } + } },{ name: "merkleId", params: { @@ -196,6 +208,18 @@ pbjs.setConfig({ name: "merkleId", expires: 30 } + }, { + name: 'admixerId', + params: { + pid: "4D393FAC-B6BB-4E19-8396-0A4813607316", // example id + e: "3d400b57e069c993babea0bd9efa79e5dc698e16c042686569faae20391fd7ea", // example hashed email (sha256) + p: "05de6c07eb3ea4bce45adca4e0182e771d80fbb99e12401416ca84ddf94c3eb9" //example hashed phone (sha256) + }, + storage: { + type: 'html5', + name: 'admixerId', + expires: 30 + } }], syncDelay: 5000 } diff --git a/test/spec/modules/admixerIdSystem_spec.js b/test/spec/modules/admixerIdSystem_spec.js new file mode 100644 index 00000000000..18107b780db --- /dev/null +++ b/test/spec/modules/admixerIdSystem_spec.js @@ -0,0 +1,81 @@ +import {admixerIdSubmodule} from 'modules/admixerIdSystem.js'; +import * as utils from 'src/utils.js'; +import {server} from 'test/mocks/xhr.js'; +import {getStorageManager} from '../../../src/storageManager.js'; + +export const storage = getStorageManager(); + +const pid = '4D393FAC-B6BB-4E19-8396-0A4813607316'; +const getIdParams = {params: {pid: pid}}; +describe('admixerId tests', function () { + let logErrorStub; + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + logErrorStub.restore(); + }); + + it('should log an error if pid configParam was not passed when getId', function () { + admixerIdSubmodule.getId(); + expect(logErrorStub.callCount).to.be.equal(1); + + admixerIdSubmodule.getId({}); + expect(logErrorStub.callCount).to.be.equal(2); + + admixerIdSubmodule.getId({params: {}}); + expect(logErrorStub.callCount).to.be.equal(3); + + admixerIdSubmodule.getId({params: {pid: 123}}); + expect(logErrorStub.callCount).to.be.equal(4); + }); + + it('should NOT call the admixer id endpoint if gdpr applies but consent string is missing', function () { + let submoduleCallback = admixerIdSubmodule.getId(getIdParams, { gdprApplies: true }); + expect(submoduleCallback).to.be.undefined; + }); + + it('should call the admixer id endpoint', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 200, + {}, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call callback with user id', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 200, + {}, + JSON.stringify({setData: {visitorid: '571058d70bce453b80e6d98b4f8a81e3'}}) + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(callBackSpy.args[0][0]).to.be.eq('571058d70bce453b80e6d98b4f8a81e3'); + }); + + it('should continue to callback if ajax response 204', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = admixerIdSubmodule.getId(getIdParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq(`https://inv-nets.admixer.net/cntcm.aspx?ssp=${pid}`); + request.respond( + 204 + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(callBackSpy.args[0][0]).to.be.undefined; + }); +}); diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index d405bc31f4f..3c852f3af5c 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -43,6 +43,7 @@ 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'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -461,7 +462,7 @@ describe('User ID', function () { }); it('handles config with no usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({}); // usersync is undefined, and no logInfo message for 'User ID - usersync config updated' @@ -469,14 +470,14 @@ describe('User ID', function () { }); it('handles config with empty usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); 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([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -487,7 +488,7 @@ describe('User ID', function () { }); it('handles config with usersync and userIds with empty names or that dont match a submodule.name', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -504,15 +505,15 @@ describe('User ID', function () { }); it('config with 1 configurations should create 1 submodules', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); 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('config with 16 configurations should result in 17 submodules add', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + it('config with 17 configurations should result in 18 submodules add', function () { + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -561,14 +562,17 @@ describe('User ID', function () { storage: {name: 'tapad_id', type: 'cookie'} }, { name: 'uid2' + }, { + name: 'admixerId', + storage: {name: 'admixerId', type: 'cookie'} }] } }); - expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 17 submodules'); + expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 18 submodules'); }); it('config syncDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -583,7 +587,7 @@ describe('User ID', function () { }); it('config auctionDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -598,7 +602,7 @@ describe('User ID', function () { }); it('config auctionDelay defaults to 0 if not a number', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -1651,7 +1655,54 @@ describe('User ID', function () { }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId, haloId, Criteo, UID 2.0 and mwOpenLinkId have data to pass', function (done) { + it('test hook from admixerId html5', function (done) { + // simulate existing browser local storage values + localStorage.setItem('admixerId', 'testadmixerId'); + localStorage.setItem('admixerId_exp', ''); + + setSubmoduleRegistry([admixerIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['admixerId', 'admixerId', 'html5'])); + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'admixer.net', + uids: [{id: 'testadmixerId', atype: 3}] + }); + }); + }); + localStorage.removeItem('admixerId'); + done(); + }, {adUnits}); + }); + + it('test hook from admixerId cookie', function (done) { + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 100000).toUTCString())); + + setSubmoduleRegistry([admixerIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['admixerId', 'admixerId', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'admixer.net', + uids: [{id: 'testadmixerId', atype: 3}] + }); + }); + }); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId, haloId, Criteo, UID 2.0, admixerId and mwOpenLinkId have data to pass', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'testunifiedid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); @@ -1668,8 +1719,9 @@ describe('User ID', function () { coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('mwol', JSON.stringify({eid: 'XX-YY-ZZ-123'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('uid2id', 'Sample_AD_Token', (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 5000).toUTCString())); - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], @@ -1684,7 +1736,8 @@ describe('User ID', function () { ['criteo', 'storage_criteo', 'cookie'], ['mwOpenLinkId', 'mwol', 'cookie'], ['tapadId', 'tapad_id', 'cookie'], - ['uid2', 'uid2id', 'cookie'])); + ['uid2', 'uid2id', 'cookie'], + ['admixerId', 'admixerId', 'cookie'])); requestBidsHook(function () { adUnits.forEach(unit => { @@ -1730,7 +1783,11 @@ describe('User ID', function () { expect(bid.userId.uid2).to.deep.equal({ id: 'Sample_AD_Token' }); - expect(bid.userIdAsEids.length).to.equal(13); + // also check that criteo id was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + + expect(bid.userIdAsEids.length).to.equal(14); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1746,11 +1803,12 @@ describe('User ID', function () { coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('mwol', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('uid2id', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, britepoolId, intentIqId, zeotapIdPlus, sharedId, criteo, netId, haloId, UID 2.0 and mwOpenLinkId have their modules added before and after init', function (done) { + it('test hook when pubCommonId, unifiedId, id5Id, britepoolId, intentIqId, zeotapIdPlus, sharedId, criteo, netId, haloId, UID 2.0, admixerId and mwOpenLinkId have their modules added before and after init', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'cookie-value-add-module-variations'}), new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); @@ -1767,6 +1825,7 @@ describe('User ID', function () { coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('mwol', JSON.stringify({eid: 'XX-YY-ZZ-123'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('uid2id', 'Sample_AD_Token', (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 5000).toUTCString())); setSubmoduleRegistry([]); @@ -1789,6 +1848,7 @@ describe('User ID', function () { attachIdSystem(mwOpenLinkIdSubModule); attachIdSystem(tapadIdSubmodule); attachIdSystem(uid2IdSubmodule); + attachIdSystem(admixerIdSubmodule); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], @@ -1803,7 +1863,8 @@ describe('User ID', function () { ['criteo', 'storage_criteo', 'cookie'], ['mwOpenLinkId', 'mwol', 'cookie'], ['tapadId', 'tapad_id', 'cookie'], - ['uid2', 'uid2id', 'cookie'])); + ['uid2', 'uid2id', 'cookie'], + ['admixerId', 'admixerId', 'cookie'])); requestBidsHook(function () { adUnits.forEach(unit => { @@ -1851,9 +1912,13 @@ describe('User ID', function () { expect(bid.userId.mwOpenLinkId).to.equal('XX-YY-ZZ-123') expect(bid.userId.uid2).to.deep.equal({ id: 'Sample_AD_Token' - }); ; + }); - expect(bid.userIdAsEids.length).to.equal(13); + // also check that admixerId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + + expect(bid.userIdAsEids.length).to.equal(14); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1869,6 +1934,7 @@ describe('User ID', function () { coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('mwol', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('uid2id', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); @@ -2125,10 +2191,11 @@ describe('User ID', function () { coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('admixerId', 'testadmixerId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('__uid2_advertising_token', 'Sample_AD_Token', (new Date(Date.now() + 5000).toUTCString())); - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, uid2IdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, uid2IdSubmodule, admixerIdSubmodule]); init(config); config.setConfig({ @@ -2154,6 +2221,8 @@ describe('User ID', function () { name: 'zeotapIdPlus' }, { name: 'haloId', storage: {name: 'haloId', type: 'cookie'} + }, { + name: 'admixerId', storage: {name: 'admixerId', type: 'cookie'} }, { name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }, { @@ -2219,7 +2288,10 @@ describe('User ID', function () { id: 'Sample_AD_Token' }); - expect(bid.userIdAsEids.length).to.equal(11); + // also check that admixerId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.admixerId'); + expect(bid.userId.admixerId).to.equal('testadmixerId'); + expect(bid.userIdAsEids.length).to.equal(12); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -2232,6 +2304,7 @@ describe('User ID', function () { coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('mwol', '', EXPIRED_COOKIE_DATE); done();