From 54efa3c0f14e9f24c33c8c891b0f8b55320829c5 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Sun, 11 Aug 2024 14:37:01 +0200 Subject: [PATCH] Weborama RTD Module: BUGFIX on user-centric profile validation (#12095) * update unit tests * fix code and doc * improve integration example * add extra test * improve logging * fix lint issues --- .../gpt/weboramaRtdProvider_example.html | 330 +++++++++--------- modules/weboramaRtdProvider.js | 286 +++++++++------ modules/weboramaRtdProvider.md | 22 +- test/spec/modules/weboramaRtdProvider_spec.js | 102 +++++- 4 files changed, 458 insertions(+), 282 deletions(-) diff --git a/integrationExamples/gpt/weboramaRtdProvider_example.html b/integrationExamples/gpt/weboramaRtdProvider_example.html index 7e75721103f..82b97696371 100644 --- a/integrationExamples/gpt/weboramaRtdProvider_example.html +++ b/integrationExamples/gpt/weboramaRtdProvider_example.html @@ -1,187 +1,201 @@ - - - - weborama rtd submodule example - - - - + + + + weborama rtd submodule example + + +
-

- test webo rtd submodule with prebid.js -

+

test webo rtd submodule with prebid.js

Basic Prebid.js Example

Div-1
-
- +
+
- - - - \ No newline at end of file + + diff --git a/modules/weboramaRtdProvider.js b/modules/weboramaRtdProvider.js index 82feec252eb..67822234840 100644 --- a/modules/weboramaRtdProvider.js +++ b/modules/weboramaRtdProvider.js @@ -100,9 +100,7 @@ * @typedef {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} CommonConf */ -import { - getGlobal -} from '../src/prebidGlobal.js'; +import { getGlobal } from '../src/prebidGlobal.js'; import { deepAccess, deepClone, @@ -111,28 +109,18 @@ import { isBoolean, isEmpty, isFn, + isNumber, isPlainObject, isStr, - logWarn, mergeDeep, prefixLog, } from '../src/utils.js'; -import { - submodule -} from '../src/hook.js'; -import { - ajax -} from '../src/ajax.js'; -import { - getStorageManager -} from '../src/storageManager.js'; -import { - MODULE_TYPE_RTD -} from '../src/activities/modules.js'; +import { submodule } from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; import adapterManager from '../src/adapterManager.js'; -import { - tryAppendQueryString -} from '../libraries/urlUtils/urlUtils.js'; +import { tryAppendQueryString } from '../libraries/urlUtils/urlUtils.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; @@ -167,7 +155,7 @@ const logger = prefixLog('[WeboramaRTD]'); export const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, - moduleName: SUBMODULE_NAME + moduleName: SUBMODULE_NAME, }); /** @@ -216,10 +204,14 @@ class WeboramaRtdProvider { sendToBidders: true, onData: () => { /* do nothing */ - } + }, }; /** @type {ModuleParams} */ - const moduleParams = Object.assign({}, globalDefaults, moduleConfig?.params || {}); + const moduleParams = Object.assign( + {}, + globalDefaults, + moduleConfig?.params || {} + ); // reset profiles @@ -229,13 +221,24 @@ class WeboramaRtdProvider { const weboCtxRequiredFields = ['token']; - this.#components.WeboCtx.initialized = this.#initSubSection(moduleParams, WEBO_CTX_CONF_SECTION, { - requiredFields: weboCtxRequiredFields, - }); - this.#components.WeboUserData.initialized = this.#initSubSection(moduleParams, WEBO_USER_DATA_CONF_SECTION, { - userConsent: userConsent || {}, - }); - this.#components.SfbxLiteData.initialized = this.#initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION); + this.#components.WeboCtx.initialized = this.#initSubSection( + moduleParams, + WEBO_CTX_CONF_SECTION, + { + requiredFields: weboCtxRequiredFields, + } + ); + this.#components.WeboUserData.initialized = this.#initSubSection( + moduleParams, + WEBO_USER_DATA_CONF_SECTION, + { + userConsent: userConsent || {}, + } + ); + this.#components.SfbxLiteData.initialized = this.#initSubSection( + moduleParams, + SFBX_LITE_DATA_CONF_SECTION + ); return Object.values(this.#components).some((c) => c.initialized); } @@ -264,15 +267,21 @@ class WeboramaRtdProvider { /** @type {WeboCtxConf} */ const weboCtxConf = moduleParams.weboCtxConf || {}; - this.#fetchContextualProfile(weboCtxConf, (data) => { - logger.logMessage('fetchContextualProfile on getBidRequestData is done'); + this.#fetchContextualProfile( + weboCtxConf, + (data) => { + logger.logMessage( + 'fetchContextualProfile on getBidRequestData is done' + ); - this.#setWeboContextualProfile(data); - }, () => { - this.#handleBidRequestData(reqBidsConfigObj, moduleParams); + this.#setWeboContextualProfile(data); + }, + () => { + this.#handleBidRequestData(reqBidsConfigObj, moduleParams); - onDone(); - }); + onDone(); + } + ); } /** @@ -344,17 +353,23 @@ class WeboramaRtdProvider { extra = extra || {}; const requiredFields = extra?.requiredFields || []; - requiredFields.forEach(field => { + requiredFields.forEach((field) => { if (!(field in weboSectionConf)) { throw `missing required field '${field}'`; } }); - if (isPlainObject(extra?.userConsent?.gdpr) && !this.#checkTCFv2(extra.userConsent.gdpr)) { + if ( + isPlainObject(extra?.userConsent?.gdpr) && + !this.#checkTCFv2(extra.userConsent.gdpr) + ) { throw 'gdpr consent not ok'; } } catch (e) { - logger.logError(`unable to initialize: error on '${subSection}' configuration:`, e); + logger.logError( + `unable to initialize: error on '${subSection}' configuration:`, + e + ); return false; } @@ -382,14 +397,18 @@ class WeboramaRtdProvider { return true; } - if (deepAccess(gdpr, 'vendorData.vendor.consents') && - deepAccess(gdpr, 'vendorData.purpose.consents')) { - return gdpr.vendorData.vendor.consents[GVLID] === true && // check weborama vendor id + if ( + deepAccess(gdpr, 'vendorData.vendor.consents') && + deepAccess(gdpr, 'vendorData.purpose.consents') + ) { + return ( + gdpr.vendorData.vendor.consents[GVLID] === true && // check weborama vendor id gdpr.vendorData.purpose.consents[1] === true && // info storage access gdpr.vendorData.purpose.consents[3] === true && // create personalized ads gdpr.vendorData.purpose.consents[4] === true && // select personalized ads gdpr.vendorData.purpose.consents[5] === true && // create personalized content - gdpr.vendorData.purpose.consents[6] === true; // select personalized content + gdpr.vendorData.purpose.consents[6] === true + ); // select personalized content } return true; @@ -439,7 +458,9 @@ class WeboramaRtdProvider { // eslint-disable-next-line no-dupe-class-members #coerceSetPrebidTargeting(submoduleParams) { try { - submoduleParams.setPrebidTargeting = this.#wrapValidatorCallback(submoduleParams.setPrebidTargeting); + submoduleParams.setPrebidTargeting = this.#wrapValidatorCallback( + submoduleParams.setPrebidTargeting + ); } catch (e) { throw `invalid setPrebidTargeting: ${e}`; } @@ -458,10 +479,13 @@ class WeboramaRtdProvider { let sendToBidders = submoduleParams.sendToBidders; if (isPlainObject(sendToBidders)) { - const sendToBiddersMap = Object.entries(sendToBidders).reduce((map, [key, value]) => { - map[key] = this.#wrapValidatorCallback(value); - return map; - }, {}); + const sendToBiddersMap = Object.entries(sendToBidders).reduce( + (map, [key, value]) => { + map[key] = this.#wrapValidatorCallback(value); + return map; + }, + {} + ); submoduleParams.sendToBidders = (bid, adUnitCode) => { const bidder = bid.bidder; @@ -482,8 +506,10 @@ class WeboramaRtdProvider { } try { - submoduleParams.sendToBidders = this.#wrapValidatorCallback(submoduleParams.sendToBidders, - (bid) => bid.bidder); + submoduleParams.sendToBidders = this.#wrapValidatorCallback( + submoduleParams.sendToBidders, + (bid) => bid.bidder + ); } catch (e) { throw `invalid sendToBidders: ${e}`; } @@ -516,9 +542,9 @@ class WeboramaRtdProvider { const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits; try { - adUnits.forEach( - adUnit => adUnit.bids?.forEach( - bid => profileHandlers.forEach(ph => { + adUnits.forEach((adUnit) => + adUnit.bids?.forEach((bid) => + profileHandlers.forEach((ph) => { // logger.logMessage(`check if bidder '${bid.bidder}' and adunit '${adUnit.code} are share ${ph.metadata.source} data`); const [data, metadata] = this.#copyDataAndMetadata(ph); @@ -534,12 +560,15 @@ class WeboramaRtdProvider { logger.logError('unable to send data to bidders:', e); } - profileHandlers.forEach(ph => { + profileHandlers.forEach((ph) => { try { const [data, metadata] = this.#copyDataAndMetadata(ph); ph.onData(data, metadata); } catch (e) { - logger.logError(`error while execute onData callback with ${ph.metadata.source}-based data:`, e); + logger.logError( + `error while execute onData callback with ${ph.metadata.source}-based data:`, + e + ); } }); } @@ -569,7 +598,8 @@ class WeboramaRtdProvider { // eslint-disable-next-line no-dupe-class-members #fetchContextualProfile(weboCtxConf, onSuccess, onDone) { const token = weboCtxConf.token; - const baseURLProfileAPI = weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API; + const baseURLProfileAPI = + weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API; let path = '/profile'; let queryString = ''; @@ -583,7 +613,10 @@ class WeboramaRtdProvider { try { assetID = weboCtxConf.assetID(); } catch (e) { - logger.logError('unexpected error while fetching asset id from callback', e); + logger.logError( + 'unexpected error while fetching asset id from callback', + e + ); onDone(); @@ -660,30 +693,43 @@ class WeboramaRtdProvider { */ // eslint-disable-next-line no-dupe-class-members #buildProfileHandlers(moduleParams) { - const steps = [{ - component: this.#components.WeboCtx, - conf: moduleParams?.weboCtxConf, - }, { - component: this.#components.WeboUserData, - conf: moduleParams?.weboUserDataConf, - }, { - component: this.#components.SfbxLiteData, - conf: moduleParams?.sfbxLiteDataConf, - }]; - - return steps.filter(step => step.component.initialized).reduce((ph, { component, conf }) => { - const user = component.user; - const source = component.source; - const callback = component.callbackBuilder(component /* equivalent to this */); - const profileHandler = this.#buildProfileHandler(conf, callback, user, source); - if (profileHandler) { - ph.push(profileHandler); - } else { - logger.logMessage(`skip ${source} profile: no data`); - } + const steps = [ + { + component: this.#components.WeboCtx, + conf: moduleParams?.weboCtxConf, + }, + { + component: this.#components.WeboUserData, + conf: moduleParams?.weboUserDataConf, + }, + { + component: this.#components.SfbxLiteData, + conf: moduleParams?.sfbxLiteDataConf, + }, + ]; + + return steps + .filter((step) => step.component.initialized) + .reduce((ph, { component, conf }) => { + const user = component.user; + const source = component.source; + const callback = component.callbackBuilder( + component /* equivalent to this */ + ); + const profileHandler = this.#buildProfileHandler( + conf, + callback, + user, + source + ); + if (profileHandler) { + ph.push(profileHandler); + } else { + logger.logMessage(`skip ${source} profile: no data`); + } - return ph; - }, []); + return ph; + }, []); } /** @@ -823,13 +869,22 @@ class WeboramaRtdProvider { // eslint-disable-next-line no-dupe-class-members #handleBidViaORTB2(reqBidsConfigObj, bidder, profile, metadata) { if (isBoolean(metadata.user)) { - logger.logMessage(`bidder '${bidder}' is not directly supported, trying set data via bidder ortb2 fpd`); + logger.logMessage( + `bidder '${bidder}' is not directly supported, trying set data via bidder ortb2 fpd` + ); const section = metadata.user ? 'user' : 'site'; const path = `${section}.ext.data`; - this.#setBidderOrtb2(reqBidsConfigObj.ortb2Fragments?.bidder, bidder, path, profile) + this.#setBidderOrtb2( + reqBidsConfigObj.ortb2Fragments?.bidder, + bidder, + path, + profile + ); } else { - logger.logMessage(`SKIP unsupported bidder '${bidder}', data from '${metadata.source}' is not defined as user or site-centric`); + logger.logMessage( + `SKIP unsupported bidder '${bidder}', data from '${metadata.source}' is not defined as user or site-centric` + ); } } /** @@ -845,7 +900,7 @@ class WeboramaRtdProvider { // eslint-disable-next-line no-dupe-class-members #setBidderOrtb2(bidderOrtb2Fragments, bidder, path, profile) { const base = `${bidder}.${path}`; - this.#assignProfileToObject(bidderOrtb2Fragments, base, profile) + this.#assignProfileToObject(bidderOrtb2Fragments, base, profile); } /** * assign profile to object @@ -861,7 +916,7 @@ class WeboramaRtdProvider { Object.entries(profile).forEach(([key, values]) => { const path = `${base}.${key}`; deepSetValue(destination, path, values); - }) + }); } /** @@ -913,6 +968,7 @@ class WeboramaRtdProvider { /** * check if profile is valid + * a valid profile must be a plain object and every value should be an array of strings or numbers * @param {*} profile * @returns {boolean} */ @@ -921,7 +977,18 @@ export function isValidProfile(profile) { return false; } - return Object.values(profile).every((field) => isArray(field) && field.every(isStr)); + return Object.values(profile).every( + (field) => isArray(field) && field.every(isStrOrNumber) + ); +} + +/** + * Return if the object is a string or number + * @param {*} object object to test + * @return {Boolean} if object is a string or number + */ +function isStrOrNumber(object) { + return isStr(object) || isNumber(object); } /** @@ -943,7 +1010,7 @@ function getContextualProfile(component /* equivalent to this */) { const defaultContextualProfile = weboCtxConf.defaultProfile || {}; return [defaultContextualProfile, true]; - } + }; } /** @@ -958,13 +1025,15 @@ function getWeboUserDataProfile(component /* equivalent to this */) { * @returns {[Profile,boolean]} weboUserData profile + isDefault boolean flag */ return function (weboUserDataConf) { - return getDataFromLocalStorage(weboUserDataConf, + return getDataFromLocalStorage( + weboUserDataConf, () => component.data, - (data) => component.data = data, + (data) => (component.data = data), DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY, LOCAL_STORAGE_USER_TARGETING_SECTION, - WEBO_USER_DATA_SOURCE_LABEL); - } + WEBO_USER_DATA_SOURCE_LABEL + ); + }; } /** @@ -979,13 +1048,15 @@ function getSfbxLiteDataProfile(component /* equivalent to this */) { * @returns {[Profile,boolean]} sfbxLiteData profile + isDefault boolean flag */ return function getSfbxLiteDataProfile(sfbxLiteDataConf) { - return getDataFromLocalStorage(sfbxLiteDataConf, + return getDataFromLocalStorage( + sfbxLiteDataConf, () => component.data, - (data) => component.data = data, + (data) => (component.data = data), DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY, LOCAL_STORAGE_LITE_TARGETING_SECTION, - SFBX_LITE_DATA_SOURCE_LABEL); - } + SFBX_LITE_DATA_SOURCE_LABEL + ); + }; } /** @@ -1008,11 +1079,23 @@ function getSfbxLiteDataProfile(component /* equivalent to this */) { * @param {string} source * @returns {[Profile,boolean]} webo (user|lite) data profile + isDefault boolean flag */ -function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalStorageProfileKey, targetingSection, source) { +function getDataFromLocalStorage( + weboDataConf, + cacheGet, + cacheSet, + defaultLocalStorageProfileKey, + targetingSection, + source +) { const defaultProfile = weboDataConf.defaultProfile || {}; - if (storage.hasLocalStorage() && storage.localStorageIsEnabled() && !cacheGet()) { - const localStorageProfileKey = weboDataConf.localStorageProfileKey || defaultLocalStorageProfileKey; + if ( + storage.hasLocalStorage() && + storage.localStorageIsEnabled() && + !cacheGet() + ) { + const localStorageProfileKey = + weboDataConf.localStorageProfileKey || defaultLocalStorageProfileKey; const entry = storage.getDataFromLocalStorage(localStorageProfileKey); if (entry) { @@ -1022,9 +1105,12 @@ function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalS const profile = data[targetingSection]; const valid = isValidProfile(profile); if (!valid) { - logWarn(`found invalid ${source} profile on local storage key ${localStorageProfileKey}, section ${targetingSection}`); + logger.logMessage( + `WARNING: found invalid ${source} profile on local storage key ${localStorageProfileKey}, section ${targetingSection}: `, + profile + ); - return; + return [defaultProfile, true]; } if (!isEmpty(data)) { diff --git a/modules/weboramaRtdProvider.md b/modules/weboramaRtdProvider.md index a8fc692ba74..11b4368a502 100644 --- a/modules/weboramaRtdProvider.md +++ b/modules/weboramaRtdProvider.md @@ -67,7 +67,7 @@ pbjs.setConfig({ enabled: true, }, sfbxLiteDataConf: { // sfbx-lite site-centric configuration, *omit if not needed* - enabled: true, + enabled: true, }, } }, @@ -215,7 +215,7 @@ A better look on the `Object` type ```javascript sendToBidders: { appnexus: true, // send profile to appnexus on all ad units - pubmatic: ['adUnitCode1'],// send profile to pubmatic on this ad units + pubmatic: ['adUnitCode1'],// send profile to pubmatic on this ad units } ``` @@ -253,7 +253,7 @@ To be possible customize the way we send data to bidders via this callback: sendToBidders: function(bid, adUnitCode, data, metadata){ if (bid.bidder == 'other'){ /* use bid object to store data based on this specific logic, like in the example below */ - + bid.params = bid.params || {}; bid.params['some_specific_key'] = data; @@ -374,7 +374,7 @@ pbjs.que.push(function () { sendToBidders: true, // override param.sendToBidders. default is true defaultProfile: { // optional, used if nothing is found webo_cs: [...], // wam custom segments - webo_audiences: [...], // wam audiences + webo_audiences: [...], // wam audiences }, enabled: true, }, @@ -485,18 +485,18 @@ pbjs.que.push(function () { params: { weboCtxConf: { token: "to-be-defined", // mandatory - setPrebidTargeting: ['adUnitCode1',...], // set target only on certain adunits + setPrebidTargeting: ['adUnitCode1',...], // set target only on certain adunits sendToBidders: ['appnexus',...], // overide, send to only some bidders enabled: true, }, weboUserDataConf: { accountId: 12345, // recommended - setPrebidTargeting: ['adUnitCode2',...], // set target only on certain adunits + setPrebidTargeting: ['adUnitCode2',...], // set target only on certain adunits sendToBidders: ['rubicon',...], // overide, send to only some bidders enabled: true, }, sfbxLiteDataConf: { - setPrebidTargeting: ['adUnitCode3',...], // set target only on certain adunits + setPrebidTargeting: ['adUnitCode3',...], // set target only on certain adunits sendToBidders: ['smartadserver',...], // overide, send to only some bidders enabled: true, } @@ -546,15 +546,15 @@ pbjs.que.push(function () { }, weboUserDataConf: { accountId: 12345, // recommended - setPrebidTargeting: ['adUnitCode1',...], // set target only on certain adunits + setPrebidTargeting: ['adUnitCode1',...], // set target only on certain adunits sendToBidders: { // send to only some bidders and adunits - 'appnexus': true, // all adunits for appnexus + 'appnexus': true, // all adunits for appnexus 'pubmatic': ['adUnitCode1',...] // some adunits for pubmatic // other bidders will be ignored }, defaultProfile: { // optional - webo_cs: ['Red'], - webo_audiences: ['bam'] + webo_cs: ['Red'], // using label + webo_audiences: [12345] // using id }, localStorageProfileKey: 'webo_wam2gam_entry', // default enabled: true, diff --git a/test/spec/modules/weboramaRtdProvider_spec.js b/test/spec/modules/weboramaRtdProvider_spec.js index d562d9ffd13..964c42eff07 100644 --- a/test/spec/modules/weboramaRtdProvider_spec.js +++ b/test/spec/modules/weboramaRtdProvider_spec.js @@ -1509,7 +1509,7 @@ describe('weboramaRtdProvider', function() { } }; const data = { - webo_cs: ['foo', 'bar'], + webo_cs: [12, 345], webo_audiences: ['baz'], }; @@ -1620,7 +1620,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -1746,7 +1746,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -1868,7 +1868,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -2013,7 +2013,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -2156,7 +2156,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -2217,7 +2217,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -2289,7 +2289,7 @@ describe('weboramaRtdProvider', function() { expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ foo: ['bar'], webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }); expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ inventory: { @@ -2312,7 +2312,7 @@ describe('weboramaRtdProvider', function() { it('should use default profile in case of nothing on local storage', function() { const defaultProfile = { - webo_audiences: ['baz'] + webo_audiences: [12345] }; const moduleConfig = { params: { @@ -2377,9 +2377,85 @@ describe('weboramaRtdProvider', function() { }) }); + it('should use default profile in case of something malformed on local storage', function() { + const defaultProfile = { + webo_audiences: [12345] + }; + const moduleConfig = { + params: { + weboUserDataConf: { + accoundId: 12345, + setPrebidTargeting: true, + defaultProfile: defaultProfile, + } + } + }; + + const malformed = { + targeting: { + webo_audiences: 'must be an array, not a string', + }, + }; + + sandbox.stub(storage, 'hasLocalStorage').returns(true); + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + sandbox.stub(storage, 'getDataFromLocalStorage') + .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) + .returns(JSON.stringify(malformed)); + + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {} + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({ + 'adunit1': defaultProfile, + }); + + expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: defaultProfile + }, + } + }); + }) + }); + it('should use default profile if cant read from local storage', function() { const defaultProfile = { - webo_audiences: ['baz'] + webo_audiences: [12345] }; let onDataResponse = {}; const moduleConfig = { @@ -2489,7 +2565,7 @@ describe('weboramaRtdProvider', function() { }; const data = { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], }; const entry = { @@ -2550,7 +2626,7 @@ describe('weboramaRtdProvider', function() { expect(targeting).to.deep.equal({ 'adunit1': { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], webo_foo: ['bar'], }, 'adunit2': data, @@ -2569,7 +2645,7 @@ describe('weboramaRtdProvider', function() { ext: { data: { webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], + webo_audiences: [12345], webo_bar: ['baz'], } },