diff --git a/modules/.submodules.json b/modules/.submodules.json index ea3f556dbb4..2e77873dc78 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -35,7 +35,8 @@ "uid2IdSystem", "unifiedIdSystem", "verizonMediaIdSystem", - "zeotapIdPlusIdSystem" + "zeotapIdPlusIdSystem", + "adqueryIdSystem" ], "adpod": [ "freeWheelAdserverVideo", diff --git a/modules/adqueryIdSystem.js b/modules/adqueryIdSystem.js new file mode 100644 index 00000000000..5357c1a1ffd --- /dev/null +++ b/modules/adqueryIdSystem.js @@ -0,0 +1,103 @@ +/** + * This module adds Adquery QID to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/adqueryIdSystem + * @requires module:modules/userId + */ + +import {ajax} from '../src/ajax.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {submodule} from '../src/hook.js'; +import * as utils from '../src/utils.js'; + +const MODULE_NAME = 'qid'; +const AU_GVLID = 902; + +export const storage = getStorageManager(AU_GVLID, 'qid'); + +/** + * Param or default. + * @param {String} param + * @param {String} defaultVal + */ +function paramOrDefault(param, defaultVal, arg) { + if (utils.isFn(param)) { + return param(arg); + } else if (utils.isStr(param)) { + return param; + } + return defaultVal; +} + +/** @type {Submodule} */ +export const adqueryIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + + /** + * IAB TCF Vendor ID + * @type {string} + */ + gvlid: AU_GVLID, + + /** + * decode the stored id value for passing to bid requests + * @function + * @param {{value:string}} value + * @returns {{qid:Object}} + */ + decode(value) { + let qid = storage.getDataFromLocalStorage('qid'); + if (utils.isStr(qid)) { + return {qid: qid}; + } + return (value && typeof value['qid'] === 'string') ? { 'qid': value['qid'] } : undefined; + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleConfig} [config] + * @returns {IdResponse|undefined} + */ + getId(config) { + if (!utils.isPlainObject(config.params)) { + config.params = {}; + } + const url = paramOrDefault(config.params.url, + `https://bidder.adquery.io/prebid/qid`, + config.params.urlArg); + + const resp = function (callback) { + let qid = storage.getDataFromLocalStorage('qid'); + if (utils.isStr(qid)) { + const responseObj = {qid: qid}; + callback(responseObj); + } else { + const callbacks = { + success: response => { + let responseObj; + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + utils.logError(error); + } + } + callback(responseObj); + }, + error: error => { + utils.logError(`${MODULE_NAME}: ID fetch encountered an error`, error); + callback(); + } + }; + ajax(url, callbacks, undefined, {method: 'GET'}); + } + }; + return {callback: resp}; + } +}; + +submodule('userId', adqueryIdSubmodule); diff --git a/modules/adqueryIdSystem.md b/modules/adqueryIdSystem.md new file mode 100644 index 00000000000..3a49ffbe4da --- /dev/null +++ b/modules/adqueryIdSystem.md @@ -0,0 +1,35 @@ +# Adquery QID + +Adquery QID Module. For assistance setting up your module please contact us at [prebid@adquery.io](prebid@adquery.io). + +### Prebid Params + +Individual params may be set for the Adquery ID Submodule. At least one identifier must be set in the params. + +``` +pbjs.setConfig({ + usersync: { + userIds: [{ + name: 'qid', + storage: { + name: 'qid', + type: 'html5' + } + }] + } +}); +``` +## Parameter Descriptions for the `usersync` Configuration Section +The below parameters apply only to the Adquery User ID Module integration. + +| Param under usersync.userIds[] | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | ID value for the Adquery ID module - `"qid"` | `"qid"` | +| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. | | +| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` | +| storage.name | Required | String | The name of the html5 local storage where the user ID will be stored. | `"qid"` | +| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` | +| value | Optional | Object | Used only if the page has a separate mechanism for storing the Adquery ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"qid": "2abf9f001fcd81241b67"}` | +| params | Optional | Object | Used to store params for the id system | +| params.url | Optional | String | Set an alternate GET url for qid with this parameter | +| params.urlArg | Optional | Object | Optional url parameter for params.url | diff --git a/modules/userId/eids.js b/modules/userId/eids.js index 87b6ecc1f1c..a290371b36d 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -257,7 +257,13 @@ const USER_IDS_CONFIG = { 'connectId': { source: 'yahoo.com', atype: 3 - } + }, + + // Adquery ID + 'qid': { + source: 'adquery.io', + atype: 1 + }, }; // this function will create an eid object for the given UserId sub-module diff --git a/modules/userId/userId.md b/modules/userId/userId.md index 095685aba3d..6364de8ea79 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -297,6 +297,14 @@ pbjs.setConfig({ type: 'html5', expires: 15 } + } + { + name: "qid", + storage: { + type: "html5", + name: "qid", + expires: 365 + } }], syncDelay: 5000 } diff --git a/test/spec/modules/adqueryIdSystem_spec.js b/test/spec/modules/adqueryIdSystem_spec.js new file mode 100644 index 00000000000..ab98b253b33 --- /dev/null +++ b/test/spec/modules/adqueryIdSystem_spec.js @@ -0,0 +1,74 @@ +import { adqueryIdSubmodule, storage } from 'modules/adqueryIdSystem.js'; +import { server } from 'test/mocks/xhr.js'; +import {amxIdSubmodule} from '../../../modules/amxIdSystem'; +import * as utils from '../../../src/utils'; + +const config = { + storage: { + type: 'html5', + }, +}; + +describe('AdqueryIdSystem', function () { + describe('qid submodule', () => { + it('should expose a "name" property containing qid', () => { + expect(adqueryIdSubmodule.name).to.equal('qid'); + }); + + it('should expose a "gvlid" property containing the GVL ID 902', () => { + expect(adqueryIdSubmodule.gvlid).to.equal(902); + }); + }); + + describe('getId', function() { + let getDataFromLocalStorageStub; + + beforeEach(function() { + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + }); + + afterEach(function () { + getDataFromLocalStorageStub.restore(); + }); + + it('gets a adqueryId', function() { + const config = { + params: {} + }; + const callbackSpy = sinon.spy(); + const callback = adqueryIdSubmodule.getId(config).callback; + callback(callbackSpy); + const request = server.requests[0]; + expect(request.url).to.eq(`https://bidder.adquery.io/prebid/qid`); + request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ qid: 'qid' })); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'qid'}); + }); + + it('gets a cached adqueryId', function() { + const config = { + params: {} + }; + getDataFromLocalStorageStub.withArgs('qid').returns('qid'); + + const callbackSpy = sinon.spy(); + const callback = adqueryIdSubmodule.getId(config).callback; + callback(callbackSpy); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'qid'}); + }); + + it('allows configurable id url', function() { + const config = { + params: { + url: 'https://bidder.adquery.io' + } + }; + const callbackSpy = sinon.spy(); + const callback = adqueryIdSubmodule.getId(config).callback; + callback(callbackSpy); + const request = server.requests[0]; + expect(request.url).to.eq('https://bidder.adquery.io'); + request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ qid: 'testqid' })); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'testqid'}); + }); + }); +}); diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index 1277486a154..83924b38a7e 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -348,6 +348,21 @@ describe('eids array generation for known sub-modules', function() { }] }); }); + + it('qid', function() { + const userId = { + qid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'adquery.io', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }); + }); }); describe('Negative case', function() { it('eids array generation for UN-known sub-module', function() { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 29b5aca630e..8ddb02138f5 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -49,6 +49,7 @@ import {flocIdSubmodule} from 'modules/flocIdSystem.js' import {amxIdSubmodule} from '../../../modules/amxIdSystem.js'; import {akamaiDAPIdSubmodule} from 'modules/akamaiDAPIdSystem.js' import {kinessoIdSubmodule} from 'modules/kinessoIdSystem.js' +import {adqueryIdSubmodule} from 'modules/adqueryIdSystem.js'; import * as mockGpt from '../integration/faker/googletag.js'; let assert = require('chai').assert; @@ -559,7 +560,7 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({}); // usersync is undefined, and no logInfo message for 'User ID - usersync config updated' @@ -567,14 +568,14 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -585,7 +586,7 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -602,7 +603,7 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig(getConfigMock(['unifiedId', 'unifiedid', 'cookie'])); @@ -623,8 +624,8 @@ describe('User ID', function () { 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]); + it('config with 24 configurations should result in 24 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, adqueryIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -689,14 +690,17 @@ describe('User ID', function () { }, { name: 'kpuid', storage: {name: 'kpuid', type: 'cookie'} + }, { + name: 'qid', + storage: {name: 'qid', type: 'html5'} }] } }); - expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 23 submodules'); + expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 24 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ @@ -712,7 +716,7 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -727,7 +731,7 @@ describe('User ID', function () { }); 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]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -1823,7 +1827,38 @@ describe('User ID', function () { }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, netId, haloId, Criteo, UID 2.0, admixerId, amxId, dmdId, kpuid and mwOpenLinkId have data to pass', function (done) { + it('test hook from qid html5', (done) => { + // simulate existing localStorage values + localStorage.setItem('qid', 'testqid'); + localStorage.setItem('qid_exp', ''); + + setSubmoduleRegistry([adqueryIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['qid', 'qid', 'html5'])); + + requestBidsHook(() => { + adUnits.forEach((adUnit) => { + adUnit.bids.forEach((bid) => { + expect(bid).to.have.deep.nested.property('userId.qid'); + expect(bid.userId.qid).to.equal('testqid'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'adquery.io', + uids: [{ + id: 'testqid', + atype: 1, + }] + }); + }); + }); + + // clear LS + localStorage.removeItem('qid'); + localStorage.removeItem('qid_exp'); + done(); + }, {adUnits}); + }); + + it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, netId, haloId, Criteo, UID 2.0, admixerId, amxId, dmdId, kpuid, qid 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())); @@ -1840,12 +1875,13 @@ describe('User ID', function () { coreStorage.setCookie('admixerId', 'testadmixerId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('deepintentId', 'testdeepintentId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('kpuid', 'KINESSO_ID', (new Date(Date.now() + 5000).toUTCString())); - // amxId only supports localStorage localStorage.setItem('amxId', 'test_amxid_id'); localStorage.setItem('amxId_exp', (new Date(Date.now() + 5000)).toUTCString()); - - setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]); + // qid only supports localStorage + localStorage.setItem('qid', 'testqid'); + localStorage.setItem('qid_exp', (new Date(Date.now() + 5000)).toUTCString()); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], @@ -1864,7 +1900,8 @@ describe('User ID', function () { ['admixerId', 'admixerId', 'cookie'], ['amxId', 'amxId', 'html5'], ['deepintentId', 'deepintentId', 'cookie'], - ['kpuid', 'kpuid', 'cookie'])); + ['kpuid', 'kpuid', 'cookie'], + ['qid', 'qid', 'html5'])); requestBidsHook(function () { adUnits.forEach(unit => { @@ -1922,7 +1959,10 @@ describe('User ID', function () { expect(bid).to.have.deep.nested.property('userId.kpuid'); expect(bid.userId.kpuid).to.equal('KINESSO_ID'); - expect(bid.userIdAsEids.length).to.equal(17); + expect(bid).to.have.deep.nested.property('userId.qid'); + expect(bid.userId.qid).to.equal('testqid'); + + expect(bid.userIdAsEids.length).to.equal(18); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1943,6 +1983,8 @@ describe('User ID', function () { coreStorage.setCookie('kpuid', EXPIRED_COOKIE_DATE); localStorage.removeItem('amxId'); localStorage.removeItem('amxId_exp'); + localStorage.removeItem('qid'); + localStorage.removeItem('qid_exp'); done(); }, {adUnits}); }); @@ -2132,8 +2174,10 @@ describe('User ID', function () { localStorage.setItem('amxId', 'test_amxid_id'); localStorage.setItem('amxId_exp', new Date(Date.now() + 5000).toUTCString()) coreStorage.setCookie('kpuid', 'KINESSO_ID', (new Date(Date.now() + 5000).toUTCString())); + localStorage.setItem('qid', 'testqid'); + localStorage.setItem('qid_exp', new Date(Date.now() + 5000).toUTCString()) - setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule]); + setSubmoduleRegistry([sharedIdSystemSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, akamaiDAPIdSubmodule, amxIdSubmodule, kinessoIdSubmodule, adqueryIdSubmodule]); init(config); config.setConfig({ @@ -2171,6 +2215,8 @@ describe('User ID', function () { name: 'amxId', storage: {name: 'amxId', type: 'html5'} }, { name: 'kpuid', storage: {name: 'kpuid', type: 'cookie'} + }, { + name: 'qid', storage: {name: 'qid', type: 'html5'} }] } }); @@ -2242,7 +2288,10 @@ describe('User ID', function () { expect(bid).to.have.deep.nested.property('userId.kpuid'); expect(bid.userId.kpuid).to.equal('KINESSO_ID'); - expect(bid.userIdAsEids.length).to.equal(15); + + expect(bid).to.have.deep.nested.property('userId.qid'); + expect(bid.userId.qid).to.equal('testqid'); + expect(bid.userIdAsEids.length).to.equal(16); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE);