diff --git a/modules/ozoneBidAdapter.js b/modules/ozoneBidAdapter.js index bbcb559b53b..2f229720208 100644 --- a/modules/ozoneBidAdapter.js +++ b/modules/ozoneBidAdapter.js @@ -1,23 +1,30 @@ -import { logInfo, logError, deepAccess, logWarn, deepSetValue, isArray, contains, isStr, mergeDeep } from '../src/utils.js'; +import { + logInfo, + logError, + deepAccess, + logWarn, + deepSetValue, + isArray, + contains, + mergeDeep, + parseUrl +} from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {getPriceBucketString} from '../src/cpmBucketManager.js'; import { Renderer } from '../src/Renderer.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; - +import {getRefererInfo} from '../src/refererDetection.js'; const BIDDER_CODE = 'ozone'; - const ORIGIN = 'https://elb.the-ozone-project.com' // applies only to auction & cookie const AUCTIONURI = '/openrtb2/auction'; const OZONECOOKIESYNC = '/static/load-cookie.html'; const OZONE_RENDERER_URL = 'https://prebid.the-ozone-project.com/ozone-renderer.js'; const ORIGIN_DEV = 'https://test.ozpr.net'; - -const OZONEVERSION = '2.7.0'; +const OZONEVERSION = '2.8.0'; export const spec = { gvlid: 524, - aliases: [{code: 'lmc', gvlid: 524}, {code: 'newspassid', gvlid: 524}], + aliases: [{code: 'lmc', gvlid: 524}], version: OZONEVERSION, code: BIDDER_CODE, supportedMediaTypes: [VIDEO, BANNER], @@ -31,10 +38,6 @@ export const spec = { 'cookieSyncUrl': ORIGIN + OZONECOOKIESYNC, 'rendererUrl': OZONE_RENDERER_URL }, - /** - * make sure that the whitelabel/default values are available in the propertyBag - * @param bid Object : the bid - */ loadWhitelabelData(bid) { if (this.propertyBag.whitelabel) { return; } this.propertyBag.whitelabel = JSON.parse(JSON.stringify(this.whitelabel_defaults)); @@ -53,7 +56,6 @@ export const spec = { this.propertyBag.whitelabel.auctionUrl = bidderConfig.endpointOverride.origin + AUCTIONURI; this.propertyBag.whitelabel.cookieSyncUrl = bidderConfig.endpointOverride.origin + OZONECOOKIESYNC; } - if (arr.hasOwnProperty('renderer')) { if (arr.renderer.match('%3A%2F%2F')) { this.propertyBag.whitelabel.rendererUrl = decodeURIComponent(arr['renderer']); @@ -92,11 +94,6 @@ export const spec = { getRendererUrl() { return this.propertyBag.whitelabel.rendererUrl; }, - /** - * Basic check to see whether required parameters are in the request. - * @param bid - * @returns {boolean} - */ isBidRequestValid(bid) { this.loadWhitelabelData(bid); logInfo('isBidRequestValid : ', config.getConfig(), bid); @@ -115,7 +112,7 @@ export const spec = { return false; } if (!(bid.params.publisherId).toString().match(/^[a-zA-Z0-9\-]{12}$/)) { - logError('VALIDATION FAILED : publisherId must be exactly 12 alphanumieric characters including hyphens', adUnitCode); + logError('VALIDATION FAILED : publisherId must be exactly 12 alphanumeric characters including hyphens', adUnitCode); return false; } if (!(bid.params.hasOwnProperty('siteId'))) { @@ -160,19 +157,10 @@ export const spec = { } return true; }, - - /** - * Split this out so that we can validate the placementId and also the override GET parameter ozstoredrequest - * @param placementId - */ isValidPlacementId(placementId) { return placementId.toString().match(/^[0-9]{10}$/); }, - buildRequests(validBidRequests, bidderRequest) { - // convert Native ORTB definition to old-style prebid native definition - validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - this.loadWhitelabelData(validBidRequests[0]); this.propertyBag.buildRequestsStart = new Date().getTime(); let whitelabelBidder = this.propertyBag.whitelabel.bidder; // by default = ozone @@ -193,14 +181,13 @@ export const spec = { singleRequest = singleRequest !== false; // undefined & true will be true logInfo(`config ${whitelabelBidder}.singleRequest : `, singleRequest); let ozoneRequest = {}; // we only want to set specific properties on this, not validBidRequests[0].params - delete ozoneRequest.test; // don't allow test to be set in the config - ONLY use $_GET['pbjs_debug'] - - let fpd = bidderRequest.ortb2; + logInfo('going to get ortb2 from bidder request...'); + let fpd = deepAccess(bidderRequest, 'ortb2', null); + logInfo('got fpd: ', fpd); if (fpd && deepAccess(fpd, 'user')) { logInfo('added FPD user object'); ozoneRequest.user = fpd.user; } - const getParams = this.getGetParametersAsObject(); const wlOztestmodeKey = whitelabelPrefix + 'testmode'; const isTestMode = getParams[wlOztestmodeKey] || null; // this can be any string, it's used for testing ads @@ -212,7 +199,8 @@ export const spec = { let placementId = placementIdOverrideFromGetParam || this.getPlacementId(ozoneBidRequest); // prefer to use a valid override param, else the bidRequest placement Id obj.id = ozoneBidRequest.bidId; // this causes an error if we change it to something else, even if you update the bidRequest object: "WARNING: Bidder ozone made bid for unknown request ID: mb7953.859498327448. Ignoring." obj.tagid = placementId; - obj.secure = window.location.protocol === 'https:' ? 1 : 0; + let parsed = parseUrl(getRefererInfo().page); + obj.secure = parsed.protocol === 'https' ? 1 : 0; let arrBannerSizes = []; if (!ozoneBidRequest.hasOwnProperty('mediaTypes')) { if (ozoneBidRequest.hasOwnProperty('sizes')) { @@ -292,7 +280,7 @@ export const spec = { } } if (fpd && deepAccess(fpd, 'site')) { - logInfo('added fpd.site'); + logInfo('adding fpd.site'); if (deepAccess(obj, 'ext.' + whitelabelBidder + '.customData.0.targeting', false)) { obj.ext[whitelabelBidder].customData[0].targeting = Object.assign(obj.ext[whitelabelBidder].customData[0].targeting, fpd.site); } else { @@ -304,7 +292,6 @@ export const spec = { } return obj; }); - let extObj = {}; extObj[whitelabelBidder] = {}; extObj[whitelabelBidder][whitelabelPrefix + '_pb_v'] = OZONEVERSION; @@ -315,8 +302,7 @@ export const spec = { extObj[whitelabelBidder].pubcid = userIds.pubcid; } } - - extObj[whitelabelBidder].pv = this.getPageId(); // attach the page ID that will be common to all auciton calls for this page if refresh() is called + extObj[whitelabelBidder].pv = this.getPageId(); // attach the page ID that will be common to all auction calls for this page if refresh() is called let ozOmpFloorDollars = this.getWhitelabelConfigItem('ozone.oz_omp_floor'); // valid only if a dollar value (typeof == 'number') logInfo(`${whitelabelPrefix}_omp_floor dollar value = `, ozOmpFloorDollars); if (typeof ozOmpFloorDollars === 'number') { @@ -327,25 +313,22 @@ export const spec = { let ozWhitelistAdserverKeys = this.getWhitelabelConfigItem('ozone.oz_whitelist_adserver_keys'); let useOzWhitelistAdserverKeys = isArray(ozWhitelistAdserverKeys) && ozWhitelistAdserverKeys.length > 0; extObj[whitelabelBidder][whitelabelPrefix + '_kvp_rw'] = useOzWhitelistAdserverKeys ? 1 : 0; - if (whitelabelBidder != 'ozone') { + if (whitelabelBidder !== 'ozone') { logInfo('setting aliases object'); extObj.prebid = {aliases: {'ozone': whitelabelBidder}}; } - if (getParams.hasOwnProperty('ozf')) { extObj[whitelabelBidder]['ozf'] = getParams.ozf == 'true' || getParams.ozf == 1 ? 1 : 0; } - if (getParams.hasOwnProperty('ozpf')) { extObj[whitelabelBidder]['ozpf'] = getParams.ozpf == 'true' || getParams.ozpf == 1 ? 1 : 0; } + if (getParams.hasOwnProperty('ozf')) { extObj[whitelabelBidder]['ozf'] = getParams.ozf === 'true' || getParams.ozf === '1' ? 1 : 0; } + if (getParams.hasOwnProperty('ozpf')) { extObj[whitelabelBidder]['ozpf'] = getParams.ozpf === 'true' || getParams.ozpf === '1' ? 1 : 0; } if (getParams.hasOwnProperty('ozrp') && getParams.ozrp.match(/^[0-3]$/)) { extObj[whitelabelBidder]['ozrp'] = parseInt(getParams.ozrp); } if (getParams.hasOwnProperty('ozip') && getParams.ozip.match(/^\d+$/)) { extObj[whitelabelBidder]['ozip'] = parseInt(getParams.ozip); } if (this.propertyBag.endpointOverride != null) { extObj[whitelabelBidder]['origin'] = this.propertyBag.endpointOverride; } - - var userExtEids = this.generateEids(validBidRequests); // generate the UserIDs in the correct format for UserId module - + let userExtEids = deepAccess(validBidRequests, '0.userIdAsEids', []); // generate the UserIDs in the correct format for UserId module ozoneRequest.site = { 'publisher': {'id': htmlParams.publisherId}, - 'page': document.location.href, + 'page': getRefererInfo().page, 'id': htmlParams.siteId }; - ozoneRequest.test = (getParams.hasOwnProperty('pbjs_debug') && getParams['pbjs_debug'] === 'true') ? 1 : 0; - + ozoneRequest.test = config.getConfig('debug') ? 1 : 0; if (bidderRequest && bidderRequest.gdprConsent) { logInfo('ADDING GDPR info'); let apiVersion = deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1); @@ -359,20 +342,18 @@ export const spec = { logInfo('WILL NOT ADD GDPR info; no bidderRequest.gdprConsent object'); } if (bidderRequest && bidderRequest.uspConsent) { - logInfo('ADDING CCPA info'); - deepSetValue(ozoneRequest, 'user.ext.uspConsent', bidderRequest.uspConsent); + logInfo('ADDING USP consent info'); + deepSetValue(ozoneRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); } else { - logInfo('WILL NOT ADD CCPA info; no bidderRequest.uspConsent.'); + logInfo('WILL NOT ADD USP consent info; no bidderRequest.uspConsent.'); } if (schain) { // we set this while iterating over the bids logInfo('schain found'); deepSetValue(ozoneRequest, 'source.ext.schain', schain); } - if (config.getConfig('coppa') === true) { deepSetValue(ozoneRequest, 'regs.coppa', 1); } - if (singleRequest) { logInfo('buildRequests starting to generate response for a single request'); ozoneRequest.id = bidderRequest.auctionId; // Unique ID of the bid request, provided by the exchange. @@ -414,19 +395,6 @@ export const spec = { logInfo(`buildRequests going to return for non-single at time ${this.propertyBag.buildRequestsEnd} (took ${this.propertyBag.buildRequestsEnd - this.propertyBag.buildRequestsStart}ms): `, arrRet); return arrRet; }, - /** - * parse a bidRequestRef that contains getFloor(), get all the data from it for the sizes & media requested for this bid & return an object containing floor data you can send to auciton endpoint - * @param bidRequestRef object = a valid bid request object reference - * @return object - * - * call: - * bidObj.getFloor({ - currency: 'USD', <- currency to return the value in - mediaType: ‘banner’, - size: ‘*’ <- or [300,250] or [[300,250],[640,480]] - * }); - * - */ getFloorObjectForAuction(bidRequestRef) { const mediaTypesSizes = { banner: deepAccess(bidRequestRef, 'mediaTypes.banner.sizes', null), @@ -447,16 +415,6 @@ export const spec = { logInfo('getFloorObjectForAuction returning : ', JSON.parse(JSON.stringify(ret))); return ret; }, - /** - * Interpret the response if the array contains BIDDER elements, in the format: [ [bidder1 bid 1, bidder1 bid 2], [bidder2 bid 1, bidder2 bid 2] ] - * NOte that in singleRequest mode this will be called once, else it will be called for each adSlot's response - * - * Updated April 2019 to return all bids, not just the one we decide is the 'winner' - * - * @param serverResponse - * @param request - * @returns {*} - */ interpretResponse(serverResponse, request) { if (request && request.bidderRequest && request.bidderRequest.bids) { this.loadWhitelabelData(request.bidderRequest.bids[0]); } let startTime = new Date().getTime(); @@ -478,15 +436,12 @@ export const spec = { enhancedAdserverTargeting = true; } logInfo('enhancedAdserverTargeting', enhancedAdserverTargeting); - serverResponse.seatbid = injectAdIdsIntoAllBidResponses(serverResponse.seatbid); // we now make sure that each bid in the bidresponse has a unique (within page) adId attribute. - serverResponse.seatbid = this.removeSingleBidderMultipleBids(serverResponse.seatbid); let ozOmpFloorDollars = this.getWhitelabelConfigItem('ozone.oz_omp_floor'); // valid only if a dollar value (typeof == 'number') let addOzOmpFloorDollars = typeof ozOmpFloorDollars === 'number'; let ozWhitelistAdserverKeys = this.getWhitelabelConfigItem('ozone.oz_whitelist_adserver_keys'); let useOzWhitelistAdserverKeys = isArray(ozWhitelistAdserverKeys) && ozWhitelistAdserverKeys.length > 0; - for (let i = 0; i < serverResponse.seatbid.length; i++) { let sb = serverResponse.seatbid[i]; for (let j = 0; j < sb.bid.length; j++) { @@ -499,17 +454,30 @@ export const spec = { let isVideo = false; let bidType = deepAccess(thisBid, 'ext.prebid.type'); logInfo(`this bid type is : ${bidType}`, j); + let adserverTargeting = {}; if (bidType === VIDEO) { isVideo = true; + this.setBidMediaTypeIfNotExist(thisBid, VIDEO); videoContext = this.getVideoContextForBidId(thisBid.bidId, request.bidderRequest.bids); // should be instream or outstream (or null if error) if (videoContext === 'outstream') { - logInfo('going to attach a renderer to OUTSTREAM video : ', j); + logInfo('going to set thisBid.mediaType = VIDEO & attach a renderer to OUTSTREAM video : ', j); thisBid.renderer = newRenderer(thisBid.bidId); } else { - logInfo('bid is not an outstream video, will not attach a renderer: ', j); + logInfo('bid is not an outstream video, will set thisBid.mediaType = VIDEO and thisBid.vastUrl and not attach a renderer: ', j); + thisBid.vastUrl = `https://${deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_host', 'missing_host')}${deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_path', 'missing_path')}?id=${deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_id', 'missing_id')}`; // need to see if this works ok for ozone + adserverTargeting['hb_cache_host'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_host', 'no-host'); + adserverTargeting['hb_cache_path'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_path', 'no-path'); + if (!thisBid.hasOwnProperty('videoCacheKey')) { + let videoCacheUuid = deepAccess(thisBid, 'ext.prebid.targeting.hb_uuid', 'no_hb_uuid'); + logInfo(`Adding videoCacheKey: ${videoCacheUuid}`); + thisBid.videoCacheKey = videoCacheUuid; + } else { + logInfo('videoCacheKey already exists on the bid object, will not add it'); + } } + } else { + this.setBidMediaTypeIfNotExist(thisBid, BANNER); } - let adserverTargeting = {}; if (enhancedAdserverTargeting) { let allBidsForThisBidid = ozoneGetAllBidsForBidId(thisBid.bidId, serverResponse.seatbid); logInfo('Going to iterate allBidsForThisBidId', allBidsForThisBidid); @@ -552,7 +520,8 @@ export const spec = { adserverTargeting[whitelabelPrefix + '_auc_id'] = String(request.bidderRequest.auctionId); adserverTargeting[whitelabelPrefix + '_winner'] = String(winningSeat); adserverTargeting[whitelabelPrefix + '_bid'] = 'true'; - + adserverTargeting[whitelabelPrefix + '_cache_id'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_cache_id', 'no-id'); + adserverTargeting[whitelabelPrefix + '_uuid'] = deepAccess(thisBid, 'ext.prebid.targeting.hb_uuid', 'no-id'); if (enhancedAdserverTargeting) { adserverTargeting[whitelabelPrefix + '_imp_id'] = String(winningBid.impid); adserverTargeting[whitelabelPrefix + '_pb_v'] = OZONEVERSION; @@ -570,26 +539,24 @@ export const spec = { } } let endTime = new Date().getTime(); - logInfo(`interpretResponse going to return at time ${endTime} (took ${endTime - startTime}ms) Time from buildRequests Start -> interpretRequests End = ${endTime - this.propertyBag.buildRequestsStart}ms`, arrAllBids); + logInfo(`interpretResponse going to return at time ${endTime} (took ${endTime - startTime}ms) Time from buildRequests Start -> interpretRequests End = ${endTime - this.propertyBag.buildRequestsStart}ms`); + logInfo('interpretResponse arrAllBids (serialised): ', JSON.parse(JSON.stringify(arrAllBids))); // this is ok to log because the renderer has not been attached yet return arrAllBids; }, - /** - * Use this to get all config values - * Now it's getting complicated with whitelabeling, this simplifies the code for getting config values. - * eg. to get whitelabelled version you just sent the ozone default string like ozone.oz_omp_floor - * @param ozoneVersion string like 'ozone.oz_omp_floor' - * @return {string|object} - */ + setBidMediaTypeIfNotExist(thisBid, mediaType) { + if (!thisBid.hasOwnProperty('mediaType')) { + logInfo(`setting thisBid.mediaType = ${mediaType}`); + thisBid.mediaType = mediaType; + } else { + logInfo(`found value for thisBid.mediaType: ${thisBid.mediaType}`); + } + }, getWhitelabelConfigItem(ozoneVersion) { - if (this.propertyBag.whitelabel.bidder == 'ozone') { return config.getConfig(ozoneVersion); } + if (this.propertyBag.whitelabel.bidder === 'ozone') { return config.getConfig(ozoneVersion); } let whitelabelledSearch = ozoneVersion.replace('ozone', this.propertyBag.whitelabel.bidder); whitelabelledSearch = whitelabelledSearch.replace('oz_', this.propertyBag.whitelabel.keyPrefix + '_'); return config.getConfig(whitelabelledSearch); }, - /** - * If a bidder bids for > 1 size for an adslot, allow only the highest bid - * @param seatbid object (serverResponse.seatbid) - */ removeSingleBidderMultipleBids(seatbid) { var ret = []; for (let i = 0; i < seatbid.length; i++) { @@ -620,7 +587,7 @@ export const spec = { } if (optionsType.iframeEnabled) { var arrQueryString = []; - if (document.location.search.match(/pbjs_debug=true/)) { + if (config.getConfig('debug')) { arrQueryString.push('pbjs_debug=true'); } arrQueryString.push('gdpr=' + (deepAccess(gdprConsent, 'gdprApplies', false) ? '1' : '0')); @@ -633,7 +600,6 @@ export const spec = { arrQueryString.push('siteId=' + this.cookieSyncBag.siteId); arrQueryString.push('cb=' + Date.now()); arrQueryString.push('bidder=' + this.propertyBag.whitelabel.bidder); - var strQueryString = arrQueryString.join('&'); if (strQueryString.length > 0) { strQueryString = '?' + strQueryString; @@ -645,11 +611,6 @@ export const spec = { }]; } }, - /** - * Find the bid matching the bidId in the request object - * get instream or outstream if this was a video request else null - * @return object|null - */ getBidRequestForBidId(bidId, arrBids) { for (let i = 0; i < arrBids.length; i++) { if (arrBids[i].bidId === bidId) { // bidId in the request comes back as impid in the seatbid bids @@ -658,13 +619,6 @@ export const spec = { } return null; }, - /** - * Locate the bid inside the arrBids for this bidId, then discover the video context, and return it. - * IF the bid cannot be found return null, else return a string. - * @param bidId - * @param arrBids - * @return string|null - */ getVideoContextForBidId(bidId, arrBids) { let requestBid = this.getBidRequestForBidId(bidId, arrBids); if (requestBid != null) { @@ -672,11 +626,6 @@ export const spec = { } return null; }, - /** - * This is used for cookie sync, not auction call - * Look for pubcid & all the other IDs according to http://prebid.org/dev-docs/modules/userId.html - * @return map - */ findAllUserIds(bidRequest) { var ret = {}; let searchKeysSingle = ['pubcid', 'tdid', 'idl_env', 'criteoId', 'lotamePanoramaId', 'fabrickId']; @@ -710,10 +659,6 @@ export const spec = { if (sharedid) { ret['sharedid'] = sharedid; } - let sharedidthird = deepAccess(bidRequest.userId, 'sharedid.third'); - if (sharedidthird) { - ret['sharedidthird'] = sharedidthird; - } } if (!ret.hasOwnProperty('pubcid')) { let pubcid = deepAccess(bidRequest, 'crumbs.pubcid'); @@ -723,20 +668,9 @@ export const spec = { } return ret; }, - /** - * Convenient method to get the value we need for the placementId - ONLY from the bidRequest - NOT taking into account any GET override ID - * @param bidRequest - * @return string - */ getPlacementId(bidRequest) { return (bidRequest.params.placementId).toString(); }, - /** - * GET parameter introduced in 2.2.0 : ozstoredrequest - * IF the GET parameter exists then it must validate for placementId correctly - * IF there's a $_GET['ozstoredrequest'] & it's valid then return this. Else return null. - * @returns null|string - */ getPlacementIdOverrideFromGetParam() { let whitelabelPrefix = this.propertyBag.whitelabel.keyPrefix; let arr = this.getGetParametersAsObject(); @@ -750,68 +684,19 @@ export const spec = { } return null; }, - /** - * Generate an object we can append to the auction request, containing user data formatted correctly for different ssps - * http://prebid.org/dev-docs/modules/userId.html - * @param validBidRequests - * @return {Array} - */ - generateEids(validBidRequests) { - let eids; - const bidRequest = validBidRequests[0]; - if (bidRequest && bidRequest.userId) { - eids = bidRequest.userIdAsEids; - this.handleTTDId(eids, validBidRequests); - } - return eids; - }, - handleTTDId(eids, validBidRequests) { - let ttdId = null; - let adsrvrOrgId = config.getConfig('adsrvrOrgId'); - if (isStr(deepAccess(validBidRequests, '0.userId.tdid'))) { - ttdId = validBidRequests[0].userId.tdid; - } else if (adsrvrOrgId && isStr(adsrvrOrgId.TDID)) { - ttdId = adsrvrOrgId.TDID; - } - if (ttdId !== null) { - eids.push({ - 'source': 'adserver.org', - 'uids': [{ - 'id': ttdId, - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - }] - }); - } - }, getGetParametersAsObject() { - let items = location.search.substr(1).split('&'); - let ret = {}; - let tmp = null; - for (let index = 0; index < items.length; index++) { - tmp = items[index].split('='); - ret[tmp[0]] = tmp[1]; - } - return ret; + let parsed = parseUrl(getRefererInfo().page); + logInfo('getGetParametersAsObject found:', parsed.search); + return parsed.search; }, - /** - * Do we have to block this request? Could be due to config values (no longer checking gdpr) - * @return {boolean|*[]} true = block the request, else false - */ blockTheRequest() { let ozRequest = this.getWhitelabelConfigItem('ozone.oz_request'); if (typeof ozRequest == 'boolean' && !ozRequest) { - logWarn(`Will not allow auction : ${this.propertyBag.whitelabel.keyPrefix}one.${this.propertyBag.whitelabel.keyPrefix}_request is set to false`); + logWarn(`Will not allow auction : ${this.propertyBag.whitelabel.keyPrefix}_request is set to false`); return true; } return false; }, - /** - * This returns a random ID for this page. It starts off with the current ms timestamp then appends a random component - * @return {string} - */ getPageId: function() { if (this.propertyBag.pageId == null) { let randPart = ''; @@ -829,14 +714,6 @@ export const spec = { ret = this._unpackVideoConfigIntoIABformat(ret, childConfig); return ret; }, - /** - * - * look in ONE object to get video config (we need to call this multiple times, so child settings override parent) - * @param ret - * @param objConfig - * @return {*} - * @private - */ _unpackVideoConfigIntoIABformat(ret, objConfig) { let arrVideoKeysAllowed = ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', 'api', 'companiontype']; for (const key in objConfig) { @@ -865,14 +742,6 @@ export const spec = { objRet = this._addVideoDefaults(objRet, childConfig, true); // child config will override parent config return objRet; }, - /** - * modify objRet, adding in default values - * @param objRet - * @param objConfig - * @param addIfMissing - * @return {*} - * @private - */ _addVideoDefaults(objRet, objConfig, addIfMissing) { let context = deepAccess(objConfig, 'context'); if (context === 'outstream') { @@ -889,15 +758,38 @@ export const spec = { objRet.skip = skippable ? 1 : 0; } return objRet; + }, + getLoggableBidObject(bid) { + let logObj = { + ad: bid.ad, + adId: bid.adId, + adUnitCode: bid.adUnitCode, + adm: bid.adm, + adomain: bid.adomain, + adserverTargeting: bid.adserverTargeting, + auctionId: bid.auctionId, + bidId: bid.bidId, + bidder: bid.bidder, + bidderCode: bid.bidderCode, + cpm: bid.cpm, + creativeId: bid.creativeId, + crid: bid.crid, + currency: bid.currency, + h: bid.h, + w: bid.w, + impid: bid.impid, + mediaType: bid.mediaType, + params: bid.params, + price: bid.price, + transactionId: bid.transactionId, + ttl: bid.ttl + }; + if (bid.hasOwnProperty('floorData')) { + logObj.floorData = bid.floorData; + } + return logObj; } }; - -/** - * add a page-level-unique adId element to all server response bids. - * NOTE that this is destructive - it mutates the serverResponse object sent in as a parameter - * @param seatbid object (serverResponse.seatbid) - * @returns seatbid object - */ export function injectAdIdsIntoAllBidResponses(seatbid) { logInfo('injectAdIdsIntoAllBidResponses', seatbid); for (let i = 0; i < seatbid.length; i++) { @@ -908,7 +800,6 @@ export function injectAdIdsIntoAllBidResponses(seatbid) { } return seatbid; } - export function checkDeepArray(Arr) { if (Array.isArray(Arr)) { if (Array.isArray(Arr[0])) { @@ -920,7 +811,6 @@ export function checkDeepArray(Arr) { return Arr; } } - export function defaultSize(thebidObj) { if (!thebidObj) { logInfo('defaultSize received empty bid obj! going to return fixed default size'); @@ -935,13 +825,6 @@ export function defaultSize(thebidObj) { returnObject.defaultHeight = checkDeepArray(sizes)[1]; return returnObject; } - -/** - * Do the messy searching for the best bid response in the serverResponse.seatbid array matching the requestBid.bidId - * @param requestBid - * @param serverResponseSeatBid - * @returns {*} bid object - */ export function ozoneGetWinnerForRequestBid(requestBidId, serverResponseSeatBid) { let thisBidWinner = null; let winningSeat = null; @@ -960,13 +843,6 @@ export function ozoneGetWinnerForRequestBid(requestBidId, serverResponseSeatBid) } return {'seat': winningSeat, 'bid': thisBidWinner}; } - -/** - * Get a list of all the bids, for this bidId. The keys in the response object will be {seatname} OR {seatname}{w}x{h} if seatname already exists - * @param matchBidId - * @param serverResponseSeatBid - * @returns {} = {ozone|320x600:{obj}, ozone|320x250:{obj}, appnexus|300x250:{obj}, ... } - */ export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { let objBids = {}; for (let j = 0; j < serverResponseSeatBid.length; j++) { @@ -986,21 +862,13 @@ export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { } return objBids; } - -/** - * Round the bid price down according to the granularity - * @param price - * @param mediaType = video, banner or native - */ export function getRoundedBid(price, mediaType) { const mediaTypeGranularity = config.getConfig(`mediaTypePriceGranularity.${mediaType}`); // might be string or object or nothing; if set then this takes precedence over 'priceGranularity' let objBuckets = config.getConfig('customPriceBucket'); // this is always an object - {} if strBuckets is not 'custom' let strBuckets = config.getConfig('priceGranularity'); // priceGranularity value, always a string ** if priceGranularity is set to an object then it's always 'custom' ** let theConfigObject = getGranularityObject(mediaType, mediaTypeGranularity, strBuckets, objBuckets); let theConfigKey = getGranularityKeyName(mediaType, mediaTypeGranularity, strBuckets); - logInfo('getRoundedBid. price:', price, 'mediaType:', mediaType, 'configkey:', theConfigKey, 'configObject:', theConfigObject, 'mediaTypeGranularity:', mediaTypeGranularity, 'strBuckets:', strBuckets); - let priceStringsObj = getPriceBucketString( price, theConfigObject, @@ -1021,13 +889,6 @@ export function getRoundedBid(price, mediaType) { } return priceStringsObj['auto']; } - -/** - * return the key to use to get the value out of the priceStrings object, taking into account anything at - * config.priceGranularity level or config.mediaType.xxx level - * I've noticed that the key specified by prebid core : config.getConfig('priceGranularity') does not properly - * take into account the 2-levels of config - */ export function getGranularityKeyName(mediaType, mediaTypeGranularity, strBuckets) { if (typeof mediaTypeGranularity === 'string') { return mediaTypeGranularity; @@ -1040,11 +901,6 @@ export function getGranularityKeyName(mediaType, mediaTypeGranularity, strBucket } return 'auto'; // fall back to a default key - should literally never be needed. } - -/** - * return the object to use to create the custom value of the priceStrings object, taking into account anything at - * config.priceGranularity level or config.mediaType.xxx level - */ export function getGranularityObject(mediaType, mediaTypeGranularity, strBuckets, objBuckets) { if (typeof mediaTypeGranularity === 'object') { return mediaTypeGranularity; @@ -1054,12 +910,6 @@ export function getGranularityObject(mediaType, mediaTypeGranularity, strBuckets } return ''; } - -/** - * We expect to be able to find a standard set of properties on winning bid objects; add them here. - * @param seatBid - * @returns {*} - */ export function ozoneAddStandardProperties(seatBid, defaultWidth, defaultHeight) { seatBid.cpm = seatBid.price; seatBid.bidId = seatBid.impid; @@ -1073,12 +923,6 @@ export function ozoneAddStandardProperties(seatBid, defaultWidth, defaultHeight) seatBid.ttl = 300; return seatBid; } - -/** - * - * @param objVideo will be like {"playerSize":[640,480],"mimes":["video/mp4"],"context":"outstream"} or POSSIBLY {"playerSize":[[640,480]],"mimes":["video/mp4"],"context":"outstream"} - * @return object {w,h} or null - */ export function getWidthAndHeightFromVideoObject(objVideo) { let playerSize = getPlayerSizeFromObject(objVideo); if (!playerSize) { @@ -1098,11 +942,6 @@ export function getWidthAndHeightFromVideoObject(objVideo) { } return ({'w': playerSize[0], 'h': playerSize[1]}); } - -/** - * @param objVideo will be like {"playerSize":[640,480],"mimes":["video/mp4"],"context":"outstream"} or POSSIBLY {"playerSize":[[640,480]],"mimes":["video/mp4"],"context":"outstream"} - * @return object {w,h} or null - */ export function playerSizeIsNestedArray(objVideo) { let playerSize = getPlayerSizeFromObject(objVideo); if (!playerSize) { @@ -1113,12 +952,6 @@ export function playerSizeIsNestedArray(objVideo) { } return (playerSize[0] && typeof playerSize[0] === 'object'); } - -/** - * Common functionality when looking at a video object, to get the playerSize - * @param objVideo - * @returns {*} - */ function getPlayerSizeFromObject(objVideo) { logInfo('getPlayerSizeFromObject received object', objVideo); let playerSize = deepAccess(objVideo, 'playerSize'); @@ -1135,10 +968,6 @@ function getPlayerSizeFromObject(objVideo) { } return playerSize; } -/* - Rendering video ads - create a renderer instance, mark it as not loaded, set a renderer function. - The renderer function will not assume that the renderer script is loaded - it will push() the ultimate render function call - */ function newRenderer(adUnitCode, rendererOptions = {}) { let isLoaded = window.ozoneVideo; logInfo(`newRenderer going to set loaded to ${isLoaded ? 'true' : 'false'}`); @@ -1151,16 +980,18 @@ function newRenderer(adUnitCode, rendererOptions = {}) { try { renderer.setRender(outstreamRender); } catch (err) { - logError('Prebid Error when calling setRender on renderer', JSON.parse(JSON.stringify(renderer)), err); + logError('Prebid Error when calling setRender on renderer', renderer, err); } + logInfo('returning renderer object'); return renderer; } function outstreamRender(bid) { - logInfo('outstreamRender called. Going to push the call to window.ozoneVideo.outstreamRender(bid) bid =', JSON.parse(JSON.stringify(bid))); + logInfo('outstreamRender called. Going to push the call to window.ozoneVideo.outstreamRender(bid) bid = (first static, then reference)'); + logInfo(JSON.parse(JSON.stringify(spec.getLoggableBidObject(bid)))); bid.renderer.push(() => { + logInfo('Going to execute window.ozoneVideo.outstreamRender'); window.ozoneVideo.outstreamRender(bid); }); } - registerBidder(spec); logInfo(`*BidAdapter ${OZONEVERSION} was loaded`); diff --git a/modules/ozoneBidAdapter.md b/modules/ozoneBidAdapter.md index ca18c962219..6f4cf752f22 100644 --- a/modules/ozoneBidAdapter.md +++ b/modules/ozoneBidAdapter.md @@ -72,3 +72,40 @@ adUnits = [{ }] }]; ``` + +//Instream Video adUnit + +adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream', + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2] + } + }, + bids: [{ + bidder: 'ozone', + params: { + publisherId: 'OZONENUK0001', + placementId: '8000000328', // or 999 + siteId: '4204204201', + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + }, + customData: [{ + "settings": {}, + "targeting": { + "key": "value", + "key2": ["value1", "value2"] + } + } + ] + + } + }] + }; +``` diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js index b29494e0b54..4c7e330b237 100644 --- a/test/spec/modules/ozoneBidAdapter_spec.js +++ b/test/spec/modules/ozoneBidAdapter_spec.js @@ -7,12 +7,6 @@ import * as utils from '../../../src/utils.js'; const OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction'; const BIDDER_CODE = 'ozone'; -/* - -NOTE - use firefox console to deep copy the objects to use here - - */ -var originalPropertyBag = {'pageId': null}; var validBidRequests = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -147,7 +141,6 @@ var validBidRequestsWithUserIdData = [ }] } ] - } ]; var validBidRequestsMinimal = [ @@ -176,7 +169,6 @@ var validBidRequestsNoSizes = [ transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; - var validBidRequestsWithBannerMediaType = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -205,7 +197,6 @@ var validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo = [ transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; - var validBidRequests1OutstreamVideo2020 = [ { 'bidder': 'ozone', @@ -288,7 +279,6 @@ var validBidRequests1OutstreamVideo2020 = [ 'bidderWinsCount': 0 } ]; - var validBidderRequest1OutstreamVideo2020 = { bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', @@ -392,84 +382,79 @@ var validBidderRequest1OutstreamVideo2020 = { } }; var validBidderRequest = { - bidderRequest: { + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + auctionStart: 1536838908986, + bidderCode: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + bids: [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - auctionStart: 1536838908986, - bidderCode: 'ozone', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', - bids: [{ - adUnitCode: 'div-gpt-ad-1460505748561-0', - auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - bidId: '2899ec066a91ff8', - bidRequestsCount: 1, - bidder: 'ozone', - bidderRequestId: '1c1586b27a1b5c8', - crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, - sizes: [[300, 250], [300, 600]], - transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' - }], - doneCbCallCount: 1, - start: 1536838908987, - timeout: 3000 - } + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000 }; - var bidderRequestWithFullGdpr = { - bidderRequest: { + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + auctionStart: 1536838908986, + bidderCode: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + bids: [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - auctionStart: 1536838908986, - bidderCode: 'ozone', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', - bids: [{ - adUnitCode: 'div-gpt-ad-1460505748561-0', - auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - bidId: '2899ec066a91ff8', - bidRequestsCount: 1, - bidder: 'ozone', - bidderRequestId: '1c1586b27a1b5c8', - crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, - sizes: [[300, 250], [300, 600]], - transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' - }], - doneCbCallCount: 1, - start: 1536838908987, - timeout: 3000, - gdprConsent: { - 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'vendorData': { - 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'gdprApplies': true, - 'hasGlobalScope': false, - 'cookieVersion': '1', - 'created': '2019-05-31T12:46:48.825', - 'lastUpdated': '2019-05-31T12:46:48.825', - 'cmpId': '28', - 'cmpVersion': '1', - 'consentLanguage': 'en', - 'consentScreen': '1', - 'vendorListVersion': 148, - 'maxVendorId': 631, - 'purposeConsents': { - '1': true, - '2': true, - '3': true, - '4': true, - '5': true - }, - 'vendorConsents': { - '468': true, - '522': true, - '524': true, /* 524 is ozone */ - '565': true, - '591': true - } + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000, + gdprConsent: { + 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'vendorData': { + 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'gdprApplies': true, + 'hasGlobalScope': false, + 'cookieVersion': '1', + 'created': '2019-05-31T12:46:48.825', + 'lastUpdated': '2019-05-31T12:46:48.825', + 'cmpId': '28', + 'cmpVersion': '1', + 'consentLanguage': 'en', + 'consentScreen': '1', + 'vendorListVersion': 148, + 'maxVendorId': 631, + 'purposeConsents': { + '1': true, + '2': true, + '3': true, + '4': true, + '5': true }, - 'gdprApplies': true - }, } + 'vendorConsents': { + '468': true, + '522': true, + '524': true, /* 524 is ozone */ + '565': true, + '591': true + } + }, + 'gdprApplies': true + } }; - var gdpr1 = { 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', 'vendorData': { @@ -502,7 +487,6 @@ var gdpr1 = { }, 'gdprApplies': true }; - var bidderRequestWithPartialGdpr = { bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', @@ -547,7 +531,6 @@ var bidderRequestWithPartialGdpr = { } } }; - var validResponse = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -604,7 +587,6 @@ var validResponse = { }, 'headers': {} }; - var validResponse2Bids = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -691,9 +673,6 @@ var validResponse2Bids = { }, 'headers': {} }; -/* -A bidder returns a bid for both sizes in an adunit - */ var validResponse2BidsSameAdunit = { 'body': { 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', @@ -780,14 +759,6 @@ var validResponse2BidsSameAdunit = { }, 'headers': {} }; -/* - -SPECIAL CONSIDERATION FOR VIDEO TESTS: - -DO NOT USE _validVideoResponse directly - the interpretResponse function will modify it (adding a renderer!!!) so all -subsequent calls will already have a renderer attached!!! - -*/ function getCleanValidVideoResponse() { return JSON.parse(JSON.stringify(_validVideoResponse)); } @@ -873,7 +844,6 @@ var _validVideoResponse = { }, 'headers': {} }; - var validBidResponse1adWith2Bidders = { 'body': { 'id': '91221f96-b931-4acc-8f05-c2a1186fa5ac', @@ -964,11 +934,6 @@ var validBidResponse1adWith2Bidders = { }, 'headers': {} }; - -/* -testing 2 ads, 2 bidders, one bidder bids for both slots in one adunit - */ - var multiRequest1 = [ { 'bidder': 'ozone', @@ -1101,182 +1066,178 @@ var multiRequest1 = [ 'bidderWinsCount': 0 } ]; - var multiBidderRequest1 = { - bidderRequest: { - 'bidderCode': 'ozone', - 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', - 'bidderRequestId': '1d03a1dfc563fc', - 'bids': [ - { - 'bidder': 'ozone', - 'params': { - 'publisherId': 'OZONERUP0001', - 'siteId': '4204204201', - 'placementId': '0420420421', - 'customData': [ - { - 'settings': {}, - 'targeting': { - 'sens': 'f', - 'pt1': '/uk', - 'pt2': 'uk', - 'pt3': 'network-front', - 'pt4': 'ng', - 'pt5': [ - 'uk' - ], - 'pt7': 'desktop', - 'pt8': [ - 'tfmqxwj7q', - 'txeh7uyo0', - 't8nxz6qzd', - 't8nyiude5', - 'sek9ghqwi' - ], - 'pt9': '|k0xw2vqzp33kklb3j5w4|||' - } - } - ] - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 + 'bidderCode': 'ozone', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'bidderRequestId': '1d03a1dfc563fc', + 'bids': [ + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' ], - [ - 300, - 600 - ] - ] + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'txeh7uyo0', + 't8nxz6qzd', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } } - }, - 'adUnitCode': 'mpu', - 'transactionId': '6480bac7-31b5-4723-9145-ad8966660651', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '2d30e86db743a8', - 'bidderRequestId': '1d03a1dfc563fc', - 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 + ] }, - { - 'bidder': 'ozone', - 'params': { - 'publisherId': 'OZONERUP0001', - 'siteId': '4204204201', - 'placementId': '0420420421', - 'customData': [ - { - 'settings': {}, - 'targeting': { - 'sens': 'f', - 'pt1': '/uk', - 'pt2': 'uk', - 'pt3': 'network-front', - 'pt4': 'ng', - 'pt5': [ - 'uk' - ], - 'pt7': 'desktop', - 'pt8': [ - 'tfmqxwj7q', - 'penl4dfdk', - 't8nxz6qzd', - 't8nyiude5', - 'sek9ghqwi' - ], - 'pt9': '|k0xw2vqzp33kklb3j5w4|||' - } - } - ] - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 728, - 90 - ], - [ - 970, - 250 - ] + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 ] - } - }, - 'adUnitCode': 'leaderboard', - 'transactionId': 'a49988e6-ae7c-46c4-9598-f18db49892a0', - 'sizes': [ - [ - 728, - 90 - ], - [ - 970, - 250 ] + } + }, + 'adUnitCode': 'mpu', + 'transactionId': '6480bac7-31b5-4723-9145-ad8966660651', + 'sizes': [ + [ + 300, + 250 ], - 'bidId': '3025f169863b7f8', - 'bidderRequestId': '1d03a1dfc563fc', - 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1592918645574, - 'timeout': 3000, - 'refererInfo': { - 'referer': 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true' - ] + [ + 300, + 600 + ] + ], + 'bidId': '2d30e86db743a8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 }, - 'gdprConsent': { - 'consentString': 'BOvy5sFO1dBa2AKAiBENDP-AAAAwVrv7_77-_9f-_f__9uj3Gr_v_f__32ccL5tv3h_7v-_7fi_-0nV4u_1tft9ydk1-5ctDztp507iakiPHmqNeb9n_mz1eZpRP58E09j53z7Ew_v8_v-b7BCPN_Y3v-8K96kA', - 'vendorData': { - 'metadata': 'BOvy5sFO1dBa2AKAiBENDPA', - 'gdprApplies': true, - 'hasGlobalConsent': false, - 'hasGlobalScope': false, - 'purposeConsents': { - '1': true, - '2': true, - '3': true, - '4': true, - '5': true - }, - 'vendorConsents': { - '1': true, - '2': true, - '3': false, - '4': true, - '5': true + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 't8nxz6qzd', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ] + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ] } }, - 'gdprApplies': true + 'adUnitCode': 'leaderboard', + 'transactionId': 'a49988e6-ae7c-46c4-9598-f18db49892a0', + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ], + 'bidId': '3025f169863b7f8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } + ], + 'auctionStart': 1592918645574, + 'timeout': 3000, + 'refererInfo': { + 'referer': 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true' + ] + }, + 'gdprConsent': { + 'consentString': 'BOvy5sFO1dBa2AKAiBENDP-AAAAwVrv7_77-_9f-_f__9uj3Gr_v_f__32ccL5tv3h_7v-_7fi_-0nV4u_1tft9ydk1-5ctDztp507iakiPHmqNeb9n_mz1eZpRP58E09j53z7Ew_v8_v-b7BCPN_Y3v-8K96kA', + 'vendorData': { + 'metadata': 'BOvy5sFO1dBa2AKAiBENDPA', + 'gdprApplies': true, + 'hasGlobalConsent': false, + 'hasGlobalScope': false, + 'purposeConsents': { + '1': true, + '2': true, + '3': true, + '4': true, + '5': true + }, + 'vendorConsents': { + '1': true, + '2': true, + '3': false, + '4': true, + '5': true + } }, - 'start': 1592918645578 - } + 'gdprApplies': true + }, + 'start': 1592918645578 }; - var multiResponse1 = { 'body': { 'id': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', @@ -1488,11 +1449,6 @@ var multiResponse1 = { }, 'headers': {} }; - -/* ---------------------end of 2 slots, 2 ---------------------------- - */ - describe('ozone Adapter', function () { describe('isBidRequestValid', function () { let validBidReq = { @@ -1503,13 +1459,10 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should return true when required params found', function () { expect(spec.isBidRequestValid(validBidReq)).to.equal(true); }); - var validBidReq2 = { - bidder: BIDDER_CODE, params: { placementId: '1310000099', @@ -1519,11 +1472,9 @@ describe('ozone Adapter', function () { }, siteId: 1234567890 } - it('should return true when required params found and all optional params are valid', function () { expect(spec.isBidRequestValid(validBidReq2)).to.equal(true); }); - var xEmptyPlacement = { bidder: BIDDER_CODE, params: { @@ -1532,11 +1483,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate empty placementId', function () { expect(spec.isBidRequestValid(xEmptyPlacement)).to.equal(false); }); - var xMissingPlacement = { bidder: BIDDER_CODE, params: { @@ -1544,11 +1493,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate missing placementId', function () { expect(spec.isBidRequestValid(xMissingPlacement)).to.equal(false); }); - var xBadPlacement = { bidder: BIDDER_CODE, params: { @@ -1557,11 +1504,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate placementId with a non-numeric value', function () { expect(spec.isBidRequestValid(xBadPlacement)).to.equal(false); }); - var xBadPlacementTooShort = { bidder: BIDDER_CODE, params: { @@ -1570,11 +1515,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate placementId with a numeric value of wrong length', function () { expect(spec.isBidRequestValid(xBadPlacementTooShort)).to.equal(false); }); - var xBadPlacementTooLong = { bidder: BIDDER_CODE, params: { @@ -1583,11 +1526,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate placementId with a numeric value of wrong length', function () { expect(spec.isBidRequestValid(xBadPlacementTooLong)).to.equal(false); }); - var xMissingPublisher = { bidder: BIDDER_CODE, params: { @@ -1595,11 +1536,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate missing publisherId', function () { expect(spec.isBidRequestValid(xMissingPublisher)).to.equal(false); }); - var xMissingSiteId = { bidder: BIDDER_CODE, params: { @@ -1607,11 +1546,9 @@ describe('ozone Adapter', function () { placementId: '1234567890', } }; - it('should not validate missing sitetId', function () { expect(spec.isBidRequestValid(xMissingSiteId)).to.equal(false); }); - var xBadPublisherTooShort = { bidder: BIDDER_CODE, params: { @@ -1620,11 +1557,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate publisherId being too short', function () { expect(spec.isBidRequestValid(xBadPublisherTooShort)).to.equal(false); }); - var xBadPublisherTooLong = { bidder: BIDDER_CODE, params: { @@ -1633,11 +1568,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate publisherId being too long', function () { expect(spec.isBidRequestValid(xBadPublisherTooLong)).to.equal(false); }); - var publisherNumericOk = { bidder: BIDDER_CODE, params: { @@ -1646,11 +1579,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should validate publisherId being 12 digits', function () { expect(spec.isBidRequestValid(publisherNumericOk)).to.equal(true); }); - var xEmptyPublisher = { bidder: BIDDER_CODE, params: { @@ -1659,11 +1590,9 @@ describe('ozone Adapter', function () { siteId: '1234567890' } }; - it('should not validate empty publisherId', function () { expect(spec.isBidRequestValid(xEmptyPublisher)).to.equal(false); }); - var xBadSite = { bidder: BIDDER_CODE, params: { @@ -1672,37 +1601,15 @@ describe('ozone Adapter', function () { siteId: '12345Z' } }; - it('should not validate bad siteId', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); - - var xBadSiteTooLong = { - bidder: BIDDER_CODE, - params: { - placementId: '1234567890', - publisherId: '9876abcd12-3', - siteId: '12345678901' - } - }; - it('should not validate siteId too long', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); - - var xBadSiteTooShort = { - bidder: BIDDER_CODE, - params: { - placementId: '1234567890', - publisherId: '9876abcd12-3', - siteId: '123456789' - } - }; - it('should not validate siteId too short', function () { expect(spec.isBidRequestValid(xBadSite)).to.equal(false); }); - var allNonStrings = { bidder: BIDDER_CODE, params: { @@ -1711,11 +1618,9 @@ describe('ozone Adapter', function () { siteId: 1234567890 } }; - it('should validate all numeric values being sent as non-string numbers', function () { expect(spec.isBidRequestValid(allNonStrings)).to.equal(true); }); - var emptySiteId = { bidder: BIDDER_CODE, params: { @@ -1724,11 +1629,9 @@ describe('ozone Adapter', function () { siteId: '' } }; - it('should not validate siteId being empty string (it is required now)', function () { expect(spec.isBidRequestValid(emptySiteId)).to.equal(false); }); - var xBadCustomData = { bidder: BIDDER_CODE, params: { @@ -1738,12 +1641,10 @@ describe('ozone Adapter', function () { 'customData': 'this aint gonna work' } }; - it('should not validate customData not being an array', function () { expect(spec.isBidRequestValid(xBadCustomData)).to.equal(false); }); - - var xBadCustomData_OLD_CUSTOMDATA_VALUE = { + var xBadCustomDataOldCustomdataValue = { bidder: BIDDER_CODE, params: { 'placementId': '1234567890', @@ -1752,12 +1653,10 @@ describe('ozone Adapter', function () { 'customData': {'gender': 'bart', 'age': 'low'} } }; - it('should not validate customData being an object, not an array', function () { - expect(spec.isBidRequestValid(xBadCustomData_OLD_CUSTOMDATA_VALUE)).to.equal(false); + expect(spec.isBidRequestValid(xBadCustomDataOldCustomdataValue)).to.equal(false); }); - - var xBadCustomData_zerocd = { + var xBadCustomDataZerocd = { bidder: BIDDER_CODE, params: { 'placementId': '1111111110', @@ -1766,12 +1665,10 @@ describe('ozone Adapter', function () { 'customData': [] } }; - it('should not validate customData array having no elements', function () { - expect(spec.isBidRequestValid(xBadCustomData_zerocd)).to.equal(false); + expect(spec.isBidRequestValid(xBadCustomDataZerocd)).to.equal(false); }); - - var xBadCustomData_notargeting = { + var xBadCustomDataNotargeting = { bidder: BIDDER_CODE, params: { 'placementId': '1234567890', @@ -1781,10 +1678,9 @@ describe('ozone Adapter', function () { } }; it('should not validate customData[] having no "targeting"', function () { - expect(spec.isBidRequestValid(xBadCustomData_notargeting)).to.equal(false); + expect(spec.isBidRequestValid(xBadCustomDataNotargeting)).to.equal(false); }); - - var xBadCustomData_tgt_not_obj = { + var xBadCustomDataTgtNotObj = { bidder: BIDDER_CODE, params: { 'placementId': '1234567890', @@ -1794,9 +1690,8 @@ describe('ozone Adapter', function () { } }; it('should not validate customData[0].targeting not being an object', function () { - expect(spec.isBidRequestValid(xBadCustomData_tgt_not_obj)).to.equal(false); + expect(spec.isBidRequestValid(xBadCustomDataTgtNotObj)).to.equal(false); }); - var xBadCustomParams = { bidder: BIDDER_CODE, params: { @@ -1821,11 +1716,9 @@ describe('ozone Adapter', function () { mimes: ['video/mp4']} } }; - it('should not validate video without context attribute', function () { expect(spec.isBidRequestValid(xBadVideoContext2)).to.equal(false); }); - let validVideoBidReq = { bidder: BIDDER_CODE, params: { @@ -1839,7 +1732,6 @@ describe('ozone Adapter', function () { 'context': 'outstream'}, } }; - it('should validate video outstream being sent', function () { expect(spec.isBidRequestValid(validVideoBidReq)).to.equal(true); }); @@ -1849,47 +1741,44 @@ describe('ozone Adapter', function () { expect(spec.isBidRequestValid(instreamVid)).to.equal(true); }); }); - describe('buildRequests', function () { + beforeEach(function () { + config.resetConfig() + }); it('sends bid request to OZONEURI via POST', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.url).to.equal(OZONEURI); expect(request.method).to.equal('POST'); }); - it('sends data as a string', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.data).to.be.a('string'); }); - it('sends all bid parameters', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); - it('adds all parameters inside the ext object only', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.data).to.be.a('string'); var data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); - it('adds all parameters inside the ext object only - lightning', function () { let localBidReq = JSON.parse(JSON.stringify(validBidRequests)); - const request = spec.buildRequests(localBidReq, validBidderRequest.bidderRequest); + const request = spec.buildRequests(localBidReq, validBidderRequest); expect(request.data).to.be.a('string'); var data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); - it('ignores ozoneData in & after version 2.1.1', function () { let validBidRequestsWithOzoneData = JSON.parse(JSON.stringify(validBidRequests)); validBidRequestsWithOzoneData[0].params.ozoneData = {'networkID': '3048', 'dfpSiteID': 'd.thesun', 'sectionID': 'homepage', 'path': '/', 'sec_id': 'null', 'sec': 'sec', 'topics': 'null', 'kw': 'null', 'aid': 'null', 'search': 'null', 'article_type': 'null', 'hide_ads': '', 'article_slug': 'null'}; - const request = spec.buildRequests(validBidRequestsWithOzoneData, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsWithOzoneData, validBidderRequest); expect(request.data).to.be.a('string'); var data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); @@ -1897,43 +1786,36 @@ describe('ozone Adapter', function () { expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); }); - it('has correct bidder', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.bidderRequest.bids[0].bidder).to.equal(BIDDER_CODE); }); - it('handles mediaTypes element correctly', function () { - const request = spec.buildRequests(validBidRequestsWithBannerMediaType, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsWithBannerMediaType, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); - it('handles no ozone or custom data', function () { - const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); - it('handles video mediaType element correctly, with outstream video', function () { - const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); - it('should not crash when there is no sizes element at all', function () { - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); - it('should be able to handle non-single requests', function () { config.setConfig({'ozone': {'singleRequest': false}}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); expect(request).to.be.a('array'); expect(request[0]).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); config.setConfig({'ozone': {'singleRequest': true}}); }); - it('should add gdpr consent information to the request when ozone is true', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest.bidderRequest; + let bidderRequest = validBidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -1944,16 +1826,14 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } } - const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); - it('should add gdpr consent information to the request when vendorData is missing vendorConsents (Mirror)', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest.bidderRequest; + let bidderRequest = validBidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -1962,16 +1842,14 @@ describe('ozone Adapter', function () { gdprApplies: true } } - const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); - it('should set regs.ext.gdpr flag to 0 when gdprApplies is false', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest.bidderRequest; + let bidderRequest = validBidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -1982,15 +1860,13 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } }; - const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs.ext.gdpr).to.equal(0); }); - it('should not have imp[N].ext.ozone.userId', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest.bidderRequest; + let bidderRequest = validBidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -2001,7 +1877,6 @@ describe('ozone Adapter', function () { purposeConsents: {1: true, 2: true, 3: true, 4: true, 5: true} } }; - let bidRequests = validBidRequests; bidRequests[0]['userId'] = { 'digitrustid': {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, @@ -2019,7 +1894,6 @@ describe('ozone Adapter', function () { expect(firstBid).to.not.have.property('userId'); delete validBidRequests[0].userId; // tidy up now, else it will screw with other tests }); - it('should pick up the value of pubcid when built using the pubCommonId module (not userId)', function () { let bidRequests = validBidRequests; bidRequests[0]['userId'] = { @@ -2031,23 +1905,13 @@ describe('ozone Adapter', function () { 'sharedid': {'id': '01EAJWWNEPN3CYMM5N8M5VXY22', 'third': '01EAJWWNEPN3CYMM5N8M5VXY22'} }; bidRequests[0]['userIdAsEids'] = validBidRequestsWithUserIdData[0]['userIdAsEids']; - const request = spec.buildRequests(bidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(bidRequests, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.pubcid).to.equal(bidRequests[0]['crumbs']['pubcid']); delete validBidRequests[0].userId; // tidy up now, else it will screw with other tests }); - it('should add a user.ext.eids object to contain user ID data in the new location (Nov 2019) Updated Aug 2020', function() { - const request = spec.buildRequests(validBidRequestsWithUserIdData, validBidderRequest.bidderRequest); - /* - 'pubcid': '12345678', - 'tdid': '1111tdid', - 'id5id': { uid: '1111', ext: { linkType: 2, abTestingControlGroup: false } }, - 'criteoId': '1111criteoId', - 'idl_env': 'liverampId', - 'parrableId': {'eid': '01.5678.parrableid'} - */ - + const request = spec.buildRequests(validBidRequestsWithUserIdData, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.user).to.exist; expect(payload.user.ext).to.exist; @@ -2067,12 +1931,11 @@ describe('ozone Adapter', function () { expect(payload.user.ext.eids[6]['source']).to.equal('parrableId'); expect(payload.user.ext.eids[6]['uids'][0]['id']['eid']).to.equal('01.5678.parrableid'); }); - it('replaces the auction url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeOrigin = 'http://sometestendpoint'; config.setConfig({'ozone': {'endpointOverride': {'origin': fakeOrigin}}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.url).to.equal(fakeOrigin + '/openrtb2/auction'); expect(request.method).to.equal('POST'); const data = JSON.parse(request.data); @@ -2080,12 +1943,11 @@ describe('ozone Adapter', function () { config.setConfig({'ozone': {'kvpPrefix': null, 'endpointOverride': null}}); spec.propertyBag.whitelabel = null; }); - it('replaces the FULL auction url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeurl = 'http://sometestendpoint/myfullurl'; config.setConfig({'ozone': {'endpointOverride': {'auctionUrl': fakeurl}}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); expect(request.url).to.equal(fakeurl); expect(request.method).to.equal('POST'); const data = JSON.parse(request.data); @@ -2093,7 +1955,6 @@ describe('ozone Adapter', function () { config.setConfig({'ozone': {'kvpPrefix': null, 'endpointOverride': null}}); spec.propertyBag.whitelabel = null; }); - it('replaces the renderer url for a config override', function () { spec.propertyBag.whitelabel = null; let fakeUrl = 'http://renderer.com'; @@ -2107,9 +1968,8 @@ describe('ozone Adapter', function () { spec.propertyBag.whitelabel = null; }); it('should generate all the adservertargeting keys correctly named', function () { - var specMock = utils.deepClone(spec); config.setConfig({'ozone': {'kvpPrefix': 'xx'}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result[0].adserverTargeting).to.have.own.property('xx_appnexus_crid'); expect(utils.deepAccess(result[0].adserverTargeting, 'xx_appnexus_crid')).to.equal('98493581'); @@ -2118,33 +1978,28 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(result[0].adserverTargeting, 'xx_size')).to.equal('300x600'); expect(utils.deepAccess(result[0].adserverTargeting, 'xx_pb_r')).to.equal('0.50'); expect(utils.deepAccess(result[0].adserverTargeting, 'xx_bid')).to.equal('true'); - config.resetConfig(); }); it('should create a meta object on each bid returned', function () { - var specMock = utils.deepClone(spec); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result[0]).to.have.own.property('meta'); expect(result[0].meta.advertiserDomains[0]).to.equal('http://prebid.org'); - config.resetConfig(); }); - it('replaces the kvp prefix ', function () { spec.propertyBag.whitelabel = null; config.setConfig({'ozone': {'kvpPrefix': 'test'}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone).to.haveOwnProperty('test_rw'); config.setConfig({'ozone': {'kvpPrefix': null}}); spec.propertyBag.whitelabel = null; }); - it('handles an alias ', function () { spec.propertyBag.whitelabel = null; config.setConfig({'lmc': {'kvpPrefix': 'test'}}); let br = JSON.parse(JSON.stringify(validBidRequests)); br[0]['bidder'] = 'lmc'; - const request = spec.buildRequests(br, validBidderRequest.bidderRequest); + const request = spec.buildRequests(br, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.lmc).to.haveOwnProperty('test_rw'); config.setConfig({'lmc': {'kvpPrefix': null}}); // I cant remove the key so set the value to null @@ -2155,7 +2010,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; - const request = specMock.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequests, validBidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(data.imp[0].ext.ozone.customData[0].targeting.oztestmode).to.equal('mytestvalue_123'); @@ -2165,7 +2020,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {ozf: '1', ozpf: '0', ozrp: '2', ozip: '123'}; }; - const request = specMock.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequests, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.ozf).to.equal(1); expect(data.ext.ozone.ozpf).to.equal(0); @@ -2177,7 +2032,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {ozf: 'false', ozpf: 'true', ozrp: 'xyz', ozip: 'hello'}; }; - const request = specMock.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequests, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.ozf).to.equal(0); expect(data.ext.ozone.ozpf).to.equal(1); @@ -2189,7 +2044,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; - const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(data.imp[0].ext.ozone.customData[0].targeting.oztestmode).to.equal('mytestvalue_123'); @@ -2199,17 +2054,16 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {}; }; - let request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + let request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); let url = request.url; expect(url).to.equal('https://elb.the-ozone-project.com/openrtb2/auction'); let cookieUrl = specMock.getCookieSyncUrl(); expect(cookieUrl).to.equal('https://elb.the-ozone-project.com/static/load-cookie.html'); - specMock = utils.deepClone(spec); specMock.getGetParametersAsObject = function() { return {'auction': 'dev', 'cookiesync': 'dev'}; }; - request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); url = request.url; expect(url).to.equal('https://test.ozpr.net/openrtb2/auction'); cookieUrl = specMock.getCookieSyncUrl(); @@ -2220,7 +2074,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': '1122334455'}; // 10 digits are valid }; - const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.oz_rw).to.equal(1); expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1122334455'); @@ -2230,71 +2084,65 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': 'BADVAL'}; // 10 digits are valid }; - const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); + const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.oz_rw).to.equal(0); expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1310000099'); }); - it('should pick up the config value of coppa & set it in the request', function () { config.setConfig({'coppa': true}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.regs).to.include.keys('coppa'); expect(payload.regs.coppa).to.equal(1); - config.resetConfig(); }); it('should pick up the config value of coppa & only set it in the request if its true', function () { config.setConfig({'coppa': false}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); const payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'regs.coppa')).to.be.undefined; - config.resetConfig(); }); it('should handle oz_omp_floor correctly', function () { config.setConfig({'ozone': {'oz_omp_floor': 1.56}}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); const payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'ext.ozone.oz_omp_floor')).to.equal(1.56); - config.resetConfig(); }); it('should ignore invalid oz_omp_floor values', function () { config.setConfig({'ozone': {'oz_omp_floor': '1.56'}}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); const payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'ext.ozone.oz_omp_floor')).to.be.undefined; - config.resetConfig(); }); it('should should contain a unique page view id in the auction request which persists across calls', function () { - let request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let request = spec.buildRequests(validBidRequests, validBidderRequest); let payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'ext.ozone.pv')).to.be.a('string'); - request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); + request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest); let payload2 = JSON.parse(request.data); expect(utils.deepAccess(payload2, 'ext.ozone.pv')).to.be.a('string'); expect(utils.deepAccess(payload2, 'ext.ozone.pv')).to.equal(utils.deepAccess(payload, 'ext.ozone.pv')); }); it('should indicate that the whitelist was used when it contains valid data', function () { config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_ozappnexus_pb', 'oz_ozappnexus_imp_id']}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.oz_kvp_rw).to.equal(1); - config.resetConfig(); }); it('should indicate that the whitelist was not used when it contains no data', function () { config.setConfig({'ozone': {'oz_whitelist_adserver_keys': []}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.oz_kvp_rw).to.equal(0); - config.resetConfig(); }); it('should indicate that the whitelist was not used when it is not set in the config', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.oz_kvp_rw).to.equal(0); }); it('should handle ortb2 site data', function () { - const ortb2 = { + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + bidderRequest.ortb2 = { 'site': { 'name': 'example_ortb2_name', 'domain': 'page.example.com', @@ -2307,14 +2155,14 @@ describe('ozone Adapter', function () { 'search': 'drill' } }; - const request = spec.buildRequests(validBidRequests, {...validBidderRequest.bidderRequest, ortb2}); + const request = spec.buildRequests(validBidRequests, bidderRequest); const payload = JSON.parse(request.data); expect(payload.imp[0].ext.ozone.customData[0].targeting.name).to.equal('example_ortb2_name'); expect(payload.user.ext).to.not.have.property('gender'); - config.resetConfig(); }); it('should add ortb2 site data when there is no customData already created', function () { - const ortb2 = { + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + bidderRequest.ortb2 = { 'site': { 'name': 'example_ortb2_name', 'domain': 'page.example.com', @@ -2327,25 +2175,25 @@ describe('ozone Adapter', function () { 'search': 'drill' } }; - const request = spec.buildRequests(validBidRequestsNoCustomData, {...validBidderRequest.bidderRequest, ortb2}); + const request = spec.buildRequests(validBidRequestsNoCustomData, bidderRequest); const payload = JSON.parse(request.data); expect(payload.imp[0].ext.ozone.customData[0].targeting.name).to.equal('example_ortb2_name'); expect(payload.imp[0].ext.ozone.customData[0].targeting).to.not.have.property('gender') - config.resetConfig(); }); it('should add ortb2 user data to the user object', function () { - const ortb2 = { + let bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); + bidderRequest.ortb2 = { 'user': { - 'gender': 'who knows these days' + 'gender': 'I identify as a box of rocks' } }; - const request = spec.buildRequests(validBidRequests, {...validBidderRequest.bidderRequest, ortb2}); + const request = spec.buildRequests(validBidRequests, bidderRequest); const payload = JSON.parse(request.data); - expect(payload.user.gender).to.equal('who knows these days'); - config.resetConfig(); + expect(payload.user.gender).to.equal('I identify as a box of rocks'); }); it('should not override the user.ext.consent string even if this is set in config ortb2', function () { - const ortb2 = { + let bidderRequest = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); + bidderRequest.ortb2 = { 'user': { 'ext': { 'consent': 'this is the consent override that shouldnt work', @@ -2353,15 +2201,14 @@ describe('ozone Adapter', function () { } } }; - const request = spec.buildRequests(validBidRequests, {...bidderRequestWithFullGdpr.bidderRequest, ortb2}); + const request = spec.buildRequests(validBidRequests, bidderRequest); const payload = JSON.parse(request.data); expect(payload.user.ext.consent2).to.equal('this should be set'); expect(payload.user.ext.consent).to.equal('BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA'); - config.resetConfig(); }); it('should have openrtb video params', function() { let allowed = ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext']; - const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest); const payload = JSON.parse(request.data); const vid = (payload.imp[0].video); const keys = Object.keys(vid); @@ -2391,13 +2238,11 @@ describe('ozone Adapter', function () { }); let localBidRequest = JSON.parse(JSON.stringify(validBidRequestsWithBannerMediaType)); localBidRequest[0].getFloor = function(x) { return {'currency': 'USD', 'floor': 0.8} }; - const request = spec.buildRequests(localBidRequest, validBidderRequest.bidderRequest); + const request = spec.buildRequests(localBidRequest, validBidderRequest); const payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'imp.0.floor.banner.currency')).to.equal('USD'); expect(utils.deepAccess(payload, 'imp.0.floor.banner.floor')).to.equal(0.8); - config.resetConfig(); }); - it('handles schain object in each bidrequest (will be the same in each br)', function () { let br = JSON.parse(JSON.stringify(validBidRequests)); let schainConfigObject = { @@ -2412,44 +2257,44 @@ describe('ozone Adapter', function () { ] }; br[0]['schain'] = schainConfigObject; - const request = spec.buildRequests(br, validBidderRequest.bidderRequest); + const request = spec.buildRequests(br, validBidderRequest); const data = JSON.parse(request.data); expect(data.source.ext).to.haveOwnProperty('schain'); expect(data.source.ext.schain).to.deep.equal(schainConfigObject); // .deep.equal() : Target object deeply (but not strictly) equals `{a: 1}` }); }); - describe('interpretResponse', function () { + beforeEach(function () { + config.resetConfig() + }) it('should build bid array', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result.length).to.equal(1); }); - it('should have all relevant fields', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); const bid = result[0]; expect(bid.cpm).to.equal(validResponse.body.seatbid[0].bid[0].cpm); expect(bid.width).to.equal(validResponse.body.seatbid[0].bid[0].width); expect(bid.height).to.equal(validResponse.body.seatbid[0].bid[0].height); }); - it('should build bid array with gdpr', function () { - let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr.bidderRequest)); + let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); validBR.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; const request = spec.buildRequests(validBidRequests, validBR); // works the old way, with GDPR not enforced by default const result = spec.interpretResponse(validResponse, request); expect(result.length).to.equal(1); }); it('should build bid array with usp/CCPA', function () { - let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr.bidderRequest)); + let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); validBR.uspConsent = '1YNY'; const request = spec.buildRequests(validBidRequests, validBR); const payload = JSON.parse(request.data); - expect(payload.user.ext.uspConsent).to.equal('1YNY'); + expect(payload.user.ext.uspConsent).not.to.exist; + expect(payload.regs.ext.us_privacy).to.equal('1YNY'); }); - it('should build bid array with only partial gdpr', function () { var validBidderRequestWithGdpr = bidderRequestWithPartialGdpr.bidderRequest; validBidderRequestWithGdpr.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; @@ -2457,26 +2302,22 @@ describe('ozone Adapter', function () { const payload = JSON.parse(request.data); expect(payload.user.ext.consent).to.be.a('string'); }); - it('should fail ok if no seatbid in server response', function () { const result = spec.interpretResponse({}, {}); expect(result).to.be.an('array'); expect(result).to.be.empty; }); - it('should fail ok if seatbid is not an array', function () { const result = spec.interpretResponse({'body': {'seatbid': 'nothing_here'}}, {}); expect(result).to.be.an('array'); expect(result).to.be.empty; }); - it('should have video renderer for outstream video', function () { const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest1OutstreamVideo2020.bidderRequest); const result = spec.interpretResponse(getCleanValidVideoResponse(), validBidderRequest1OutstreamVideo2020); const bid = result[0]; expect(bid.renderer).to.be.an.instanceOf(Renderer); }); - it('should have NO video renderer for instream video', function () { let instreamRequestsObj = JSON.parse(JSON.stringify(validBidRequests1OutstreamVideo2020)); instreamRequestsObj[0].mediaTypes.video.context = 'instream'; @@ -2487,99 +2328,87 @@ describe('ozone Adapter', function () { const bid = result[0]; expect(bid.hasOwnProperty('renderer')).to.be.false; }); - it('should correctly parse response where there are more bidders than ad slots', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validBidResponse1adWith2Bidders, request); expect(result.length).to.equal(2); }); - it('should have a ttl of 600', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result[0].ttl).to.equal(300); }); - it('should handle oz_omp_floor_dollars correctly, inserting 1 as necessary', function () { config.setConfig({'ozone': {'oz_omp_floor': 0.01}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.equal('1'); - config.resetConfig(); }); it('should handle oz_omp_floor_dollars correctly, inserting 0 as necessary', function () { config.setConfig({'ozone': {'oz_omp_floor': 2.50}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.equal('0'); - config.resetConfig(); }); it('should handle missing oz_omp_floor_dollars correctly, inserting nothing', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.be.undefined; }); it('should handle ext.bidder.ozone.floor correctly, setting flr & rid as necessary', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); let vres = JSON.parse(JSON.stringify(validResponse)); vres.body.seatbid[0].bid[0].ext.bidder.ozone = {floor: 1, ruleId: 'ZjbsYE1q'}; const result = spec.interpretResponse(vres, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr')).to.equal(1); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid')).to.equal('ZjbsYE1q'); - config.resetConfig(); }); it('should handle ext.bidder.ozone.floor correctly, inserting 0 as necessary', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); let vres = JSON.parse(JSON.stringify(validResponse)); vres.body.seatbid[0].bid[0].ext.bidder.ozone = {floor: 0, ruleId: 'ZjbXXE1q'}; const result = spec.interpretResponse(vres, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr')).to.equal(0); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid')).to.equal('ZjbXXE1q'); - config.resetConfig(); }); it('should handle ext.bidder.ozone.floor correctly, inserting nothing as necessary', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); let vres = JSON.parse(JSON.stringify(validResponse)); vres.body.seatbid[0].bid[0].ext.bidder.ozone = {}; const result = spec.interpretResponse(vres, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr', null)).to.equal(null); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid', null)).to.equal(null); - config.resetConfig(); }); it('should handle ext.bidder.ozone.floor correctly, when bidder.ozone is not there', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); let vres = JSON.parse(JSON.stringify(validResponse)); const result = spec.interpretResponse(vres, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr', null)).to.equal(null); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid', null)).to.equal(null); - config.resetConfig(); }); it('should handle a valid whitelist, removing items not on the list & leaving others', function () { config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_appnexus_crid', 'oz_appnexus_adId']}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adId')).to.equal('2899ec066a91ff8-0-oz-0'); - config.resetConfig(); }); it('should ignore a whitelist if enhancedAdserverTargeting is false', function () { config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_appnexus_crid', 'oz_appnexus_imp_id'], 'enhancedAdserverTargeting': false}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_imp_id')).to.be.undefined; - config.resetConfig(); }); it('should correctly handle enhancedAdserverTargeting being false', function () { config.setConfig({'ozone': {'enhancedAdserverTargeting': false}}); - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.interpretResponse(validResponse, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_imp_id')).to.be.undefined; - config.resetConfig(); }); it('should add flr into ads request if floor exists in the auction response', function () { - const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest); let validres = JSON.parse(JSON.stringify(validResponse2Bids)); validres.body.seatbid[0].bid[0].ext.bidder.ozone = {'floor': 1}; const result = spec.interpretResponse(validres, request); @@ -2587,7 +2416,7 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_flr', '')).to.equal(''); }); it('should add rid into ads request if ruleId exists in the auction response', function () { - const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest); let validres = JSON.parse(JSON.stringify(validResponse2Bids)); validres.body.seatbid[0].bid[0].ext.bidder.ozone = {'ruleId': 123}; const result = spec.interpretResponse(validres, request); @@ -2595,13 +2424,13 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_rid', '')).to.equal(''); }); it('should add oz_ozappnexus_sid (cid value) for all appnexus bids', function () { - const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest); let validres = JSON.parse(JSON.stringify(validResponse2BidsSameAdunit)); const result = spec.interpretResponse(validres, request); expect(utils.deepAccess(result[0].adserverTargeting, 'oz_ozappnexus_sid')).to.equal(result[0].cid); }); it('should add unique adId values to each bid', function() { - const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest); let validres = JSON.parse(JSON.stringify(validResponse2BidsSameAdunit)); const result = spec.interpretResponse(validres, request); expect(result.length).to.equal(1); @@ -2610,7 +2439,7 @@ describe('ozone Adapter', function () { }); it('should correctly process an auction with 2 adunits & multiple bidders one of which bids for both adslots', function() { let validres = JSON.parse(JSON.stringify(multiResponse1)); - let request = spec.buildRequests(multiRequest1, multiBidderRequest1.bidderRequest); + let request = spec.buildRequests(multiRequest1, multiBidderRequest1); let result = spec.interpretResponse(validres, request); expect(result.length).to.equal(4); // one of the 5 bids will have been removed expect(result[1]['price']).to.equal(0.521); @@ -2620,15 +2449,28 @@ describe('ozone Adapter', function () { validres = JSON.parse(JSON.stringify(multiResponse1)); validres.body.seatbid[0].bid[1].price = 1.1; validres.body.seatbid[0].bid[1].cpm = 1.1; - request = spec.buildRequests(multiRequest1, multiBidderRequest1.bidderRequest); + request = spec.buildRequests(multiRequest1, multiBidderRequest1); result = spec.interpretResponse(validres, request); expect(result[1]['price']).to.equal(1.1); expect(result[1]['impid']).to.equal('3025f169863b7f8'); expect(result[1]['id']).to.equal('18552976939844681'); expect(result[1]['adserverTargeting']['oz_ozappnexus_adId']).to.equal('3025f169863b7f8-0-oz-1'); }); + it('should add mediaType: banner for a banner ad', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(result[0].mediaType).to.equal('banner'); + }); + it('should add mediaType: video for a video ad', function () { + let instreamRequestsObj = JSON.parse(JSON.stringify(validBidRequests1OutstreamVideo2020)); + instreamRequestsObj[0].mediaTypes.video.context = 'instream'; + let instreamBidderReq = JSON.parse(JSON.stringify(validBidderRequest1OutstreamVideo2020)); + instreamBidderReq.bidderRequest.bids[0].mediaTypes.video.context = 'instream'; + const result = spec.interpretResponse(getCleanValidVideoResponse(), instreamBidderReq); + const bid = result[0]; + expect(bid.mediaType).to.equal('video'); + }); }); - describe('userSyncs', function () { it('should fail gracefully if no server response', function () { const result = spec.getUserSyncs('bad', false, gdpr1); @@ -2639,7 +2481,7 @@ describe('ozone Adapter', function () { expect(result).to.be.empty; }); it('should append the various values if they exist', function() { - spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1); expect(result).to.be.an('array'); expect(result[0].url).to.include('publisherId=9876abcd12-3'); @@ -2648,19 +2490,18 @@ describe('ozone Adapter', function () { expect(result[0].url).to.include('gdpr_consent=BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA'); }); it('should append ccpa (usp data)', function() { - spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1, '1YYN'); expect(result).to.be.an('array'); expect(result[0].url).to.include('usp_consent=1YYN'); }); it('should use "" if no usp is sent to cookieSync', function() { - spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + spec.buildRequests(validBidRequests, validBidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1); expect(result).to.be.an('array'); expect(result[0].url).to.include('usp_consent=&'); }); }); - describe('video object utils', function () { it('should find width & height from video object', function () { let obj = {'playerSize': [640, 480], 'mimes': ['video/mp4'], 'context': 'outstream'}; @@ -2715,7 +2556,7 @@ describe('ozone Adapter', function () { expect(result).to.be.null; }); it('should add oz_appnexus_dealid into ads request if dealid exists in the auction response', function () { - const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest); let validres = JSON.parse(JSON.stringify(validResponse2Bids)); validres.body.seatbid[0].bid[0].dealid = '1234'; const result = spec.interpretResponse(validres, request); @@ -2723,7 +2564,6 @@ describe('ozone Adapter', function () { expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_dealid', '')).to.equal(''); }); }); - describe('default size', function () { it('should should return default sizes if no obj is sent', function () { let obj = ''; @@ -2732,7 +2572,6 @@ describe('ozone Adapter', function () { expect(result.defaultWidth).to.equal(300); }); }); - describe('getGranularityKeyName', function() { it('should return a string granularity as-is', function() { const result = getGranularityKeyName('', 'this is it', ''); @@ -2747,7 +2586,6 @@ describe('ozone Adapter', function () { expect(result).to.equal('string buckets'); }); }); - describe('getGranularityObject', function() { it('should return an object as-is', function() { const result = getGranularityObject('', {'name': 'mark'}, '', ''); @@ -2758,19 +2596,19 @@ describe('ozone Adapter', function () { expect(result.name).to.equal('rupert'); }); }); - describe('blockTheRequest', function() { + beforeEach(function () { + config.resetConfig() + }) it('should return true if oz_request is false', function() { config.setConfig({'ozone': {'oz_request': false}}); - let result = spec.blockTheRequest(bidderRequestWithFullGdpr); + let result = spec.blockTheRequest(); expect(result).to.be.true; - config.resetConfig(); }); it('should return false if oz_request is true', function() { config.setConfig({'ozone': {'oz_request': true}}); - let result = spec.blockTheRequest(bidderRequestWithFullGdpr); + let result = spec.blockTheRequest(); expect(result).to.be.false; - config.resetConfig(); }); }); describe('getPageId', function() { @@ -2876,11 +2714,10 @@ describe('ozone Adapter', function () { expect(response[1].bid.length).to.equal(2); }); }); - /** - * spec.getWhitelabelConfigItem test - get a config value for a whitelabelled bidder, - * from a standard ozone.oz_xxxx_yyy string - */ describe('getWhitelabelConfigItem', function() { + beforeEach(function () { + config.resetConfig() + }) it('should fetch the whitelabelled equivalent config value correctly', function () { var specMock = utils.deepClone(spec); config.setConfig({'ozone': {'oz_omp_floor': 'ozone-floor-value'}}); @@ -2896,7 +2733,26 @@ describe('ozone Adapter', function () { let testKey2 = 'ozone.singleRequest'; let markbidder_config2 = specMock.getWhitelabelConfigItem(testKey2); expect(markbidder_config2).to.equal('markbidder-singlerequest-value'); - config.resetConfig(); + }); + }); + describe('setBidMediaTypeIfNotExist', function() { + it('should leave the bid object alone if it already contains mediaType', function() { + let thisBid = {mediaType: 'marktest'}; + spec.setBidMediaTypeIfNotExist(thisBid, 'replacement'); + expect(thisBid.mediaType).to.equal('marktest'); + }); + it('should change the bid object if it doesnt already contain mediaType', function() { + let thisBid = {someKey: 'someValue'}; + spec.setBidMediaTypeIfNotExist(thisBid, 'replacement'); + expect(thisBid.mediaType).to.equal('replacement'); + }); + }); + describe('getLoggableBidObject', function() { + it('should return an object without a "renderer" element', function () { + let obj = {'renderer': {}, 'somevalue': '', 'h': 100}; + let ret = spec.getLoggableBidObject(obj); + expect(ret).to.not.have.own.property('renderer'); + expect(ret.h).to.equal(100); }); }); });