diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js
index b6f4523bb50..03423a028b4 100644
--- a/modules/openxBidAdapter.js
+++ b/modules/openxBidAdapter.js
@@ -1,609 +1,238 @@
-import {
- _each,
- _map,
- convertTypes,
- deepAccess,
- deepSetValue,
- inIframe,
- isArray,
- parseSizesInput,
- parseUrl
-} from '../src/utils.js';
import {config} from '../src/config.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
+import * as utils from '../src/utils.js';
+import {mergeDeep} from '../src/utils.js';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
-import {includes} from '../src/polyfill.js';
+import {ortbConverter} from '../libraries/ortbConverter/converter.js';
-const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
-const VIDEO_TARGETING = ['startdelay', 'mimes', 'minduration', 'maxduration',
- 'startdelay', 'skippable', 'playbackmethod', 'api', 'protocols', 'boxingallowed',
- 'linearity', 'delivery', 'protocol', 'placement', 'minbitrate', 'maxbitrate'];
-const BIDDER_CODE = 'openx';
-const BIDDER_CONFIG = 'hb_pb';
-const BIDDER_VERSION = '3.0.3';
-
-const DEFAULT_CURRENCY = 'USD';
-
-export const USER_ID_CODE_TO_QUERY_ARG = {
- britepoolid: 'britepoolid', // BritePool ID
- criteoId: 'criteoid', // CriteoID
- fabrickId: 'nuestarid', // Fabrick ID by Nuestar
- hadronId: 'audigentid', // Hadron ID from Audigent
- id5id: 'id5id', // ID5 ID
- idl_env: 'lre', // LiveRamp IdentityLink
- IDP: 'zeotapid', // zeotapIdPlus ID+
- idxId: 'idxid', // idIDx,
- intentIqId: 'intentiqid', // IntentIQ ID
- lipb: 'lipbid', // LiveIntent ID
- lotamePanoramaId: 'lotameid', // Lotame Panorama ID
- merkleId: 'merkleid', // Merkle ID
- netId: 'netid', // netID
- parrableId: 'parrableid', // Parrable ID
- pubcid: 'pubcid', // PubCommon ID
- quantcastId: 'quantcastid', // Quantcast ID
- tapadId: 'tapadid', // Tapad Id
- tdid: 'ttduuid', // The Trade Desk Unified ID
- uid2: 'uid2', // Unified ID 2.0
- admixerId: 'admixerid', // AdMixer ID
- deepintentId: 'deepintentid', // DeepIntent ID
- dmdId: 'dmdid', // DMD Marketing Corp ID
- nextrollId: 'nextrollid', // NextRoll ID
- novatiq: 'novatiqid', // Novatiq ID
- mwOpenLinkId: 'mwopenlinkid', // MediaWallah OpenLink ID
- dapId: 'dapid', // Akamai DAP ID
- amxId: 'amxid', // AMX RTB ID
- kpuid: 'kpuid', // Kinesso ID
- publinkId: 'publinkid', // Publisher Link
- naveggId: 'naveggid', // Navegg ID
- imuid: 'imuid', // IM-UID by Intimate Merger
- adtelligentId: 'adtelligentid' // Adtelligent ID
+const bidderConfig = 'hb_pb_ortb';
+const bidderVersion = '2.0';
+export const REQUEST_URL = 'https://rtb.openx.net/openrtbb/prebidjs';
+export const SYNC_URL = 'https://u.openx.net/w/1.0/pd';
+export const DEFAULT_PH = '2d1251ae-7f3a-47cf-bd2a-2f288854a0ba';
+export const spec = {
+ code: 'openx',
+ supportedMediaTypes: [BANNER, VIDEO],
+ isBidRequestValid,
+ buildRequests,
+ interpretResponse,
+ getUserSyncs,
+ transformBidParams
};
-export const spec = {
- code: BIDDER_CODE,
- gvlid: 69,
- supportedMediaTypes: SUPPORTED_AD_TYPES,
- isBidRequestValid: function (bidRequest) {
- const hasDelDomainOrPlatform = bidRequest.params.delDomain || bidRequest.params.platform;
- if (deepAccess(bidRequest, 'mediaTypes.banner') && hasDelDomainOrPlatform) {
- return !!bidRequest.params.unit || deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
- }
+registerBidder(spec);
- return !!(bidRequest.params.unit && hasDelDomainOrPlatform);
+const converter = ortbConverter({
+ context: {
+ netRevenue: true,
+ ttl: 300
},
- buildRequests: function (bidRequests, bidderRequest) {
- if (bidRequests.length === 0) {
- return [];
- }
-
- let requests = [];
- let [videoBids, bannerBids] = partitionByVideoBids(bidRequests);
-
- // build banner requests
- if (bannerBids.length > 0) {
- requests.push(buildOXBannerRequest(bannerBids, bidderRequest));
- }
- // build video requests
- if (videoBids.length > 0) {
- videoBids.forEach(videoBid => {
- requests.push(buildOXVideoRequest(videoBid, bidderRequest))
- });
+ imp(buildImp, bidRequest, context) {
+ const imp = buildImp(bidRequest, context);
+ mergeDeep(imp, {
+ tagid: bidRequest.params.unit,
+ ext: {
+ divid: bidRequest.adUnitCode
+ }
+ });
+ if (bidRequest.params.customParams) {
+ utils.deepSetValue(imp, 'ext.customParams', bidRequest.params.customParams);
}
-
- return requests;
- },
- interpretResponse: function ({body: oxResponseObj}, serverRequest) {
- let mediaType = getMediaTypeFromRequest(serverRequest);
-
- return mediaType === VIDEO ? createVideoBidResponses(oxResponseObj, serverRequest.payload)
- : createBannerBidResponses(oxResponseObj, serverRequest.payload);
- },
- getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
- if (syncOptions.iframeEnabled || syncOptions.pixelEnabled) {
- let pixelType = syncOptions.iframeEnabled ? 'iframe' : 'image';
- let url = deepAccess(responses, '0.body.ads.pixels') ||
- deepAccess(responses, '0.body.pixels') ||
- generateDefaultSyncUrl(gdprConsent, uspConsent);
-
- return [{
- type: pixelType,
- url: url
- }];
+ if (bidRequest.params.customFloor && !imp.bidfloor) {
+ imp.bidfloor = bidRequest.params.customFloor;
}
+ return imp;
},
- transformBidParams: function(params, isOpenRtb) {
- return convertTypes({
- 'unit': 'string',
- 'customFloor': 'number'
- }, params);
- }
-};
-
-function generateDefaultSyncUrl(gdprConsent, uspConsent) {
- let url = 'https://u.openx.net/w/1.0/pd';
- let queryParamStrings = [];
-
- if (gdprConsent) {
- queryParamStrings.push('gdpr=' + (gdprConsent.gdprApplies ? 1 : 0));
- queryParamStrings.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''));
- }
-
- // CCPA
- if (uspConsent) {
- queryParamStrings.push('us_privacy=' + encodeURIComponent(uspConsent));
- }
-
- return `${url}${queryParamStrings.length > 0 ? '?' + queryParamStrings.join('&') : ''}`;
-}
-
-function isVideoRequest(bidRequest) {
- return (deepAccess(bidRequest, 'mediaTypes.video') && !deepAccess(bidRequest, 'mediaTypes.banner')) || bidRequest.mediaType === VIDEO;
-}
-
-function createBannerBidResponses(oxResponseObj, {bids, startTime}) {
- let adUnits = oxResponseObj.ads.ad;
- let bidResponses = [];
- for (let i = 0; i < adUnits.length; i++) {
- let adUnit = adUnits[i];
- let adUnitIdx = parseInt(adUnit.idx, 10);
- let bidResponse = {};
-
- bidResponse.requestId = bids[adUnitIdx].bidId;
-
- if (adUnit.pub_rev) {
- bidResponse.cpm = Number(adUnit.pub_rev) / 1000;
- } else {
- // No fill, do not add the bidresponse
- continue;
+ request(buildRequest, imps, bidderRequest, context) {
+ const req = buildRequest(imps, bidderRequest, context);
+ mergeDeep(req, {
+ at: 1,
+ ext: {
+ bc: `${bidderConfig}_${bidderVersion}`
+ }
+ })
+ const bid = context.bidRequests[0];
+ if (bid.params.coppa) {
+ utils.deepSetValue(req, 'regs.coppa', 1);
}
- let creative = adUnit.creative[0];
- if (creative) {
- bidResponse.width = creative.width;
- bidResponse.height = creative.height;
+ if (bid.params.doNotTrack) {
+ utils.deepSetValue(req, 'device.dnt', 1);
}
- bidResponse.creativeId = creative.id;
- bidResponse.ad = adUnit.html;
- if (adUnit.deal_id) {
- bidResponse.dealId = adUnit.deal_id;
+ if (bid.params.platform) {
+ utils.deepSetValue(req, 'ext.platform', bid.params.platform);
}
- // default 5 mins
- bidResponse.ttl = 300;
- // true is net, false is gross
- bidResponse.netRevenue = true;
- bidResponse.currency = adUnit.currency;
-
- // additional fields to add
- if (adUnit.tbd) {
- bidResponse.tbd = adUnit.tbd;
+ if (bid.params.delDomain) {
+ utils.deepSetValue(req, 'ext.delDomain', bid.params.delDomain);
}
- bidResponse.ts = adUnit.ts;
-
- bidResponse.meta = {};
- if (adUnit.brand_id) {
- bidResponse.meta.brandId = adUnit.brand_id;
+ if (bid.params.response_template_name) {
+ utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name);
}
-
- if (adUnit.adomain && length(adUnit.adomain) > 0) {
- bidResponse.meta.advertiserDomains = adUnit.adomain;
- } else {
- bidResponse.meta.advertiserDomains = [];
+ if (bid.params.test) {
+ req.test = 1
}
-
- if (adUnit.adv_id) {
- bidResponse.meta.dspid = adUnit.adv_id;
- }
-
- bidResponses.push(bidResponse);
- }
- return bidResponses;
-}
-
-function getViewportDimensions(isIfr) {
- let width;
- let height;
- let tWin = window;
- let tDoc = document;
- let docEl = tDoc.documentElement;
- let body;
-
- if (isIfr) {
- try {
- tWin = window.top;
- tDoc = window.top.document;
- } catch (e) {
- return;
+ return req;
+ },
+ bidResponse(buildBidResponse, bid, context) {
+ const bidResponse = buildBidResponse(bid, context);
+ if (bid.ext) {
+ bidResponse.meta.networkId = bid.ext.dsp_id;
+ bidResponse.meta.advertiserId = bid.ext.buyer_id;
+ bidResponse.meta.brandId = bid.ext.brand_id;
+ }
+ const {ortbResponse} = context;
+ if (ortbResponse.ext && ortbResponse.ext.paf) {
+ bidResponse.meta.paf = Object.assign({}, ortbResponse.ext.paf);
+ bidResponse.meta.paf.content_id = utils.deepAccess(bid, 'ext.paf.content_id');
+ }
+ return bidResponse;
+ },
+ response(buildResponse, bidResponses, ortbResponse, context) {
+ // pass these from request to the responses for use in userSync
+ const {ortbRequest} = context;
+ if (ortbRequest.ext) {
+ if (ortbRequest.ext.delDomain) {
+ utils.deepSetValue(ortbResponse, 'ext.delDomain', ortbRequest.ext.delDomain);
+ }
+ if (ortbRequest.ext.platform) {
+ utils.deepSetValue(ortbResponse, 'ext.platform', ortbRequest.ext.platform);
+ }
}
- body = tDoc.body;
-
- width = tWin.innerWidth || docEl.clientWidth || body.clientWidth;
- height = tWin.innerHeight || docEl.clientHeight || body.clientHeight;
- } else {
- width = tWin.innerWidth || docEl.clientWidth;
- height = tWin.innerHeight || docEl.clientHeight;
- }
-
- return `${width}x${height}`;
-}
-
-function formatCustomParms(customKey, customParams) {
- let value = customParams[customKey];
- if (isArray(value)) {
- // if value is an array, join them with commas first
- value = value.join(',');
- }
- // return customKey=customValue format, escaping + to . and / to _
- return (customKey.toLowerCase() + '=' + value.toLowerCase()).replace('+', '.').replace('/', '_')
-}
-
-function partitionByVideoBids(bidRequests) {
- return bidRequests.reduce(function (acc, bid) {
- // Fallback to banner ads if nothing specified
- if (isVideoRequest(bid)) {
- acc[0].push(bid);
+ const response = buildResponse(bidResponses, ortbResponse, context);
+ // TODO: we may want to standardize this and move fledge logic to ortbConverter
+ let fledgeAuctionConfigs = utils.deepAccess(ortbResponse, 'ext.fledge_auction_configs');
+ if (fledgeAuctionConfigs) {
+ fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => {
+ return {
+ bidId,
+ config: Object.assign({
+ auctionSignals: {},
+ }, cfg)
+ }
+ });
+ return {
+ bids: response.bids,
+ fledgeAuctionConfigs,
+ }
} else {
- acc[1].push(bid);
- }
- return acc;
- }, [[], []]);
-}
-
-function getMediaTypeFromRequest(serverRequest) {
- return /avjp$/.test(serverRequest.url) ? VIDEO : BANNER;
-}
-
-function buildCommonQueryParamsFromBids(bids, bidderRequest) {
- const isInIframe = inIframe();
- let defaultParams;
-
- defaultParams = {
- ju: bidderRequest.refererInfo.page,
- ch: document.charSet || document.characterSet,
- res: `${screen.width}x${screen.height}x${screen.colorDepth}`,
- ifr: isInIframe,
- tz: new Date().getTimezoneOffset(),
- tws: getViewportDimensions(isInIframe),
- be: 1,
- bc: bids[0].params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
- dddid: _map(bids, bid => bid.transactionId).join(','),
- nocache: new Date().getTime()
- };
-
- const userAgentClientHints = deepAccess(bidderRequest, 'ortb2.device.sua');
- if (userAgentClientHints) {
- defaultParams.sua = JSON.stringify(userAgentClientHints);
- }
-
- const userDataSegments = buildFpdQueryParams('user.data', bidderRequest.ortb2);
- if (userDataSegments.length > 0) {
- defaultParams.sm = userDataSegments;
- }
-
- const siteContentDataSegments = buildFpdQueryParams('site.content.data', bidderRequest.ortb2);
- if (siteContentDataSegments.length > 0) {
- defaultParams.scsm = siteContentDataSegments;
- }
-
- if (bids[0].params.platform) {
- defaultParams.ph = bids[0].params.platform;
- }
-
- if (bidderRequest.gdprConsent) {
- let gdprConsentConfig = bidderRequest.gdprConsent;
-
- if (gdprConsentConfig.consentString !== undefined) {
- defaultParams.gdpr_consent = gdprConsentConfig.consentString;
- }
-
- if (gdprConsentConfig.gdprApplies !== undefined) {
- defaultParams.gdpr = gdprConsentConfig.gdprApplies ? 1 : 0;
+ return response.bids
}
-
- if (config.getConfig('consentManagement.cmpApi') === 'iab') {
- defaultParams.x_gdpr_f = 1;
- }
- }
-
- if (bidderRequest && bidderRequest.uspConsent) {
- defaultParams.us_privacy = bidderRequest.uspConsent;
- }
-
- // normalize publisher common id
- if (deepAccess(bids[0], 'crumbs.pubcid')) {
- deepSetValue(bids[0], 'userId.pubcid', deepAccess(bids[0], 'crumbs.pubcid'));
- }
- defaultParams = appendUserIdsToQueryParams(defaultParams, bids[0].userId);
-
- // supply chain support
- if (bids[0].schain) {
- defaultParams.schain = serializeSupplyChain(bids[0].schain);
- }
-
- return defaultParams;
-}
-
-function buildFpdQueryParams(fpdPath, ortb2) {
- const firstPartyData = deepAccess(ortb2, fpdPath);
- if (!Array.isArray(firstPartyData) || !firstPartyData.length) {
- return '';
- }
- const fpd = firstPartyData
- .filter(
- data => (Array.isArray(data.segment) &&
- data.segment.length > 0 &&
- data.name !== undefined &&
- data.name.length > 0)
- )
- .reduce((acc, data) => {
- const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
- acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
- return acc;
- }, {})
- return Object.keys(fpd)
- .map((name, _) => name + ':' + fpd[name].join('|'))
- .join(',')
-}
-
-function appendUserIdsToQueryParams(queryParams, userIds) {
- _each(userIds, (userIdObjectOrValue, userIdProviderKey) => {
- const key = USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey];
-
- if (USER_ID_CODE_TO_QUERY_ARG.hasOwnProperty(userIdProviderKey)) {
- switch (userIdProviderKey) {
- case 'merkleId':
- queryParams[key] = userIdObjectOrValue.id;
- break;
- case 'uid2':
- queryParams[key] = userIdObjectOrValue.id;
- break;
- case 'lipb':
- queryParams[key] = userIdObjectOrValue.lipbid;
- if (Array.isArray(userIdObjectOrValue.segments) && userIdObjectOrValue.segments.length > 0) {
- const liveIntentSegments = 'liveintent:' + userIdObjectOrValue.segments.join('|');
- queryParams.sm = `${queryParams.sm ? queryParams.sm + ',' : ''}${liveIntentSegments}`;
+ },
+ overrides: {
+ imp: {
+ bidfloor(setBidFloor, imp, bidRequest, context) {
+ // enforce floors should always be in USD
+ // TODO: does it make sense that request.cur can be any currency, but request.imp[].bidfloorcur must be USD?
+ const floor = {};
+ setBidFloor(floor, bidRequest, {...context, currency: 'USD'});
+ if (floor.bidfloorcur === 'USD') {
+ Object.assign(imp, floor);
+ }
+ },
+ video(orig, imp, bidRequest, context) {
+ if (FEATURES.VIDEO) {
+ // `orig` is the video imp processor, which looks at bidRequest.mediaTypes[VIDEO]
+ // to populate imp.video
+ // alter its input `bidRequest` to also pick up parameters from `bidRequest.params`
+ let videoParams = bidRequest.mediaTypes[VIDEO];
+ if (videoParams) {
+ videoParams = Object.assign({}, videoParams, bidRequest.params.video);
+ bidRequest = {...bidRequest, mediaTypes: {[VIDEO]: videoParams}}
+ }
+ orig(imp, bidRequest, context);
+ if (imp.video && videoParams?.context === 'outstream') {
+ imp.video.placement = imp.video.placement || 4;
}
- break;
- case 'parrableId':
- queryParams[key] = userIdObjectOrValue.eid;
- break;
- case 'id5id':
- queryParams[key] = userIdObjectOrValue.uid;
- break;
- case 'novatiq':
- queryParams[key] = userIdObjectOrValue.snowflake;
- break;
- default:
- queryParams[key] = userIdObjectOrValue;
+ }
}
}
- });
-
- return queryParams;
-}
-
-function serializeSupplyChain(supplyChain) {
- return `${supplyChain.ver},${supplyChain.complete}!${serializeSupplyChainNodes(supplyChain.nodes)}`;
-}
-
-function serializeSupplyChainNodes(supplyChainNodes) {
- const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
+ }
+});
- return supplyChainNodes.map(supplyChainNode => {
- return supplyChainNodePropertyOrder.map(property => supplyChainNode[property] || '')
- .join(',');
- }).join('!');
+function transformBidParams(params, isOpenRtb) {
+ return utils.convertTypes({
+ 'unit': 'string',
+ 'customFloor': 'number'
+ }, params);
}
-function buildOXBannerRequest(bids, bidderRequest) {
- let customParamsForAllBids = [];
- let hasCustomParam = false;
- let queryParams = buildCommonQueryParamsFromBids(bids, bidderRequest);
- let auids = _map(bids, bid => bid.params.unit);
+function isBidRequestValid(bidRequest) {
+ const hasDelDomainOrPlatform = bidRequest.params.delDomain ||
+ bidRequest.params.platform;
- queryParams.aus = _map(bids, bid => parseSizesInput(bid.mediaTypes.banner.sizes).join(',')).join('|');
- queryParams.divids = _map(bids, bid => encodeURIComponent(bid.adUnitCode)).join(',');
- // gpid
- queryParams.aucs = _map(bids, function (bid) {
- let gpid = deepAccess(bid, 'ortb2Imp.ext.data.pbadslot');
- return encodeURIComponent(gpid || '')
- }).join(',');
-
- if (auids.some(auid => auid)) {
- queryParams.auid = auids.join(',');
- }
-
- if (bids.some(bid => bid.params.doNotTrack)) {
- queryParams.ns = 1;
+ if (utils.deepAccess(bidRequest, 'mediaTypes.banner') &&
+ hasDelDomainOrPlatform) {
+ return !!bidRequest.params.unit ||
+ utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
}
- if (config.getConfig('coppa') === true || bids.some(bid => bid.params.coppa)) {
- queryParams.tfcd = 1;
- }
+ return !!(bidRequest.params.unit && hasDelDomainOrPlatform);
+}
- bids.forEach(function (bid) {
- if (bid.params.customParams) {
- let customParamsForBid = _map(Object.keys(bid.params.customParams), customKey => formatCustomParms(customKey, bid.params.customParams));
- let formattedCustomParams = window.btoa(customParamsForBid.join('&'));
- hasCustomParam = true;
- customParamsForAllBids.push(formattedCustomParams);
- } else {
- customParamsForAllBids.push('');
- }
+function buildRequests(bids, bidderRequest) {
+ let videoBids = bids.filter(bid => isVideoBid(bid));
+ let bannerBids = bids.filter(bid => isBannerBid(bid));
+ let requests = bannerBids.length ? [createRequest(bannerBids, bidderRequest, BANNER)] : [];
+ videoBids.forEach(bid => {
+ requests.push(createRequest([bid], bidderRequest, VIDEO));
});
- if (hasCustomParam) {
- queryParams.tps = customParamsForAllBids.join(',');
- }
-
- enrichQueryWithFloors(queryParams, BANNER, bids);
-
- let url = queryParams.ph
- ? `https://u.openx.net/w/1.0/arj`
- : `https://${bids[0].params.delDomain}/w/1.0/arj`;
-
- return {
- method: 'GET',
- url: url,
- data: queryParams,
- payload: {'bids': bids, 'startTime': new Date()}
- };
+ return requests;
}
-function buildOXVideoRequest(bid, bidderRequest) {
- let oxVideoParams = generateVideoParameters(bid, bidderRequest);
- let url = oxVideoParams.ph
- ? `https://u.openx.net/v/1.0/avjp`
- : `https://${bid.params.delDomain}/v/1.0/avjp`;
+function createRequest(bidRequests, bidderRequest, mediaType) {
return {
- method: 'GET',
- url: url,
- data: oxVideoParams,
- payload: {'bid': bid, 'startTime': new Date()}
- };
-}
-
-function generateVideoParameters(bid, bidderRequest) {
- const videoMediaType = deepAccess(bid, `mediaTypes.video`);
- let queryParams = buildCommonQueryParamsFromBids([bid], bidderRequest);
- let oxVideoConfig = deepAccess(bid, 'params.video') || {};
- let context = deepAccess(bid, 'mediaTypes.video.context');
- let playerSize = deepAccess(bid, 'mediaTypes.video.playerSize');
- let width;
- let height;
-
- // normalize config for video size
- if (isArray(bid.sizes) && bid.sizes.length === 2 && !isArray(bid.sizes[0])) {
- width = parseInt(bid.sizes[0], 10);
- height = parseInt(bid.sizes[1], 10);
- } else if (isArray(bid.sizes) && isArray(bid.sizes[0]) && bid.sizes[0].length === 2) {
- width = parseInt(bid.sizes[0][0], 10);
- height = parseInt(bid.sizes[0][1], 10);
- } else if (isArray(playerSize) && playerSize.length === 2) {
- width = parseInt(playerSize[0], 10);
- height = parseInt(playerSize[1], 10);
- }
-
- let openRtbParams = {w: width, h: height};
-
- // legacy openrtb params could be in video, openrtb, or video.openrtb
- let legacyParams = bid.params.video || bid.params.openrtb || {};
- if (legacyParams.openrtb) {
- legacyParams = legacyParams.openrtb;
- }
- // support for video object or full openrtb object
- if (isArray(legacyParams.imp)) {
- legacyParams = legacyParams.imp[0].video;
+ method: 'POST',
+ url: config.getConfig('openxOrtbUrl') || REQUEST_URL,
+ data: converter.toORTB({bidRequests, bidderRequest, context: {mediaType}})
}
- Object.keys(legacyParams)
- .filter(param => includes(VIDEO_TARGETING, param))
- .forEach(param => openRtbParams[param] = legacyParams[param]);
-
- // 5.0 openrtb video params
- Object.keys(videoMediaType)
- .filter(param => includes(VIDEO_TARGETING, param))
- .forEach(param => openRtbParams[param] = videoMediaType[param]);
-
- let openRtbReq = {
- imp: [
- {
- video: openRtbParams
- }
- ]
- };
-
- queryParams['openrtb'] = JSON.stringify(openRtbReq);
-
- queryParams.auid = bid.params.unit;
- // override prebid config with openx config if available
- queryParams.vwd = width || oxVideoConfig.vwd;
- queryParams.vht = height || oxVideoConfig.vht;
-
- if (context === 'outstream') {
- queryParams.vos = '101';
- }
-
- if (oxVideoConfig.mimes) {
- queryParams.vmimes = oxVideoConfig.mimes;
- }
-
- if (bid.params.test) {
- queryParams.vtest = 1;
- }
-
- let gpid = deepAccess(bid, 'ortb2Imp.ext.data.pbadslot');
- if (gpid) {
- queryParams.aucs = encodeURIComponent(gpid);
- }
-
- // each video bid makes a separate request
- enrichQueryWithFloors(queryParams, VIDEO, [bid]);
-
- return queryParams;
}
-function createVideoBidResponses(response, {bid, startTime}) {
- let bidResponses = [];
-
- if (response !== undefined && response.vastUrl !== '' && response.pub_rev > 0) {
- let vastQueryParams = parseUrl(response.vastUrl).search || {};
- let bidResponse = {};
- bidResponse.requestId = bid.bidId;
- if (response.deal_id) {
- bidResponse.dealId = response.deal_id;
- }
- // default 5 mins
- bidResponse.ttl = 300;
- // true is net, false is gross
- bidResponse.netRevenue = true;
- bidResponse.currency = response.currency;
- bidResponse.cpm = parseInt(response.pub_rev, 10) / 1000;
- bidResponse.width = parseInt(response.width, 10);
- bidResponse.height = parseInt(response.height, 10);
- bidResponse.creativeId = response.adid;
- bidResponse.vastUrl = response.vastUrl;
- bidResponse.mediaType = VIDEO;
+function isVideoBid(bid) {
+ return utils.deepAccess(bid, 'mediaTypes.video');
+}
- // enrich adunit with vast parameters
- response.ph = vastQueryParams.ph;
- response.colo = vastQueryParams.colo;
- response.ts = vastQueryParams.ts;
+function isBannerBid(bid) {
+ return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid);
+}
- bidResponses.push(bidResponse);
+function interpretResponse(resp, req) {
+ if (!resp.body) {
+ resp.body = {nbr: 0};
}
-
- return bidResponses;
+ return converter.fromORTB({request: req.data, response: resp.body});
}
-function enrichQueryWithFloors(queryParams, mediaType, bids) {
- let customFloorsForAllBids = [];
- let hasCustomFloor = false;
- bids.forEach(function (bid) {
- let floor = getBidFloor(bid, mediaType);
-
- if (floor) {
- customFloorsForAllBids.push(floor);
- hasCustomFloor = true;
+/**
+ * @param syncOptions
+ * @param responses
+ * @param gdprConsent
+ * @param uspConsent
+ * @return {{type: (string), url: (*|string)}[]}
+ */
+function getUserSyncs(syncOptions, responses, gdprConsent, uspConsent) {
+ if (syncOptions.iframeEnabled || syncOptions.pixelEnabled) {
+ let pixelType = syncOptions.iframeEnabled ? 'iframe' : 'image';
+ let queryParamStrings = [];
+ let syncUrl = SYNC_URL;
+ if (gdprConsent) {
+ queryParamStrings.push('gdpr=' + (gdprConsent.gdprApplies ? 1 : 0));
+ queryParamStrings.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''));
+ }
+ if (uspConsent) {
+ queryParamStrings.push('us_privacy=' + encodeURIComponent(uspConsent));
+ }
+ if (responses.length > 0 && responses[0].body && responses[0].body.ext) {
+ const ext = responses[0].body.ext;
+ if (ext.delDomain) {
+ syncUrl = `https://${ext.delDomain}/w/1.0/pd`
+ } else if (ext.platform) {
+ queryParamStrings.push('ph=' + ext.platform)
+ }
} else {
- customFloorsForAllBids.push(0);
+ queryParamStrings.push('ph=' + DEFAULT_PH)
}
- });
- if (hasCustomFloor) {
- queryParams.aumfs = customFloorsForAllBids.join(',');
+ return [{
+ type: pixelType,
+ url: `${syncUrl}${queryParamStrings.length > 0 ? '?' + queryParamStrings.join('&') : ''}`
+ }];
}
}
-
-function getBidFloor(bidRequest, mediaType) {
- let floorInfo = {};
- const currency = config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY;
-
- if (typeof bidRequest.getFloor === 'function') {
- floorInfo = bidRequest.getFloor({
- currency: currency,
- mediaType: mediaType,
- size: '*'
- });
- }
- let floor = floorInfo.floor || bidRequest.params.customFloor || 0;
-
- return Math.round(floor * 1000); // normalize to micro currency
-}
-
-registerBidder(spec);
diff --git a/modules/openxBidAdapter.md b/modules/openxBidAdapter.md
index 0690bf6b4fc..a39aa1580cd 100644
--- a/modules/openxBidAdapter.md
+++ b/modules/openxBidAdapter.md
@@ -9,30 +9,31 @@ Maintainer: team-openx@openx.com
# Description
Module that connects to OpenX's demand sources.
-Note there is an updated version of the OpenX bid adapter called openxOrtbBidAdapter.
-Publishers are welcome to test the other adapter and give feedback. Please note you should only include either openxBidAdapter or openxOrtbBidAdapter in your build.
+Note that this adapter mirrors openxOrtbBidAdapter and any updates must be
+completed in both adapters.
+openxOrtbBidAdapter will be removed in a future release and should not be used.
+Please note you should only include either openxBidAdapter or openxOrtbBidAdapter in your build.
# Bid Parameters
## Banner
-| Name | Scope | Type | Description | Example |
-|---------------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|
-| `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" |
-| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" |
-| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` |
-| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50
**WARNING:**
Misuse of this parameter can impact revenue
Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module is prioritized over customFloor if both are present. | 1.50 |
-| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.
**WARNING:**
Request-level setting. May impact revenue. | true |
-| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true |
-
-** platform is deprecated. Please use delDomain instead. If you have any questions please contact your representative.
+| Name | Scope | Type | Description | Example
+| ---- | ----- | ---- | ----------- | -------
+| `delDomain` or `platform` | required | String | OpenX delivery domain or platform id provided by your OpenX representative. | "PUBLISHER-d.openx.net" or "555not5a-real-plat-form-id0123456789"
+| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122"
+| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}`
+| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50
**WARNING:**
Misuse of this parameter can impact revenue | 1.50
+| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.
**WARNING:**
Request-level setting. May impact revenue. | true
+| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. Use of `pbjs.setConfig({coppa: true});` is now preferred. | true
## Video
-| Name | Scope | Type | Description | Example |
-|-------------|----------|--------------------|--------------------------------------------------------------|----------------------------------------------------------------|
-| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" |
-| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" |
-| `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` |
+| Name | Scope | Type | Description | Example
+| ---- | ----- | ---- | ----------- | -------
+| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122"
+| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net"
+| `video` | optional | OpenRTB video subtypes | Use of adUnit.mediaTypes.video is now preferred. | `{ video: {mimes: ['video/mp4']}`
+
# Example
```javascript
@@ -70,7 +71,8 @@ var adUnits = [
mediaTypes: {
video: {
playerSize: [640, 480],
- context: 'instream'
+ context: 'instream',
+ mimes: ['video/x-ms-wmv, video/mp4']
}
},
bids: [{
@@ -79,10 +81,10 @@ var adUnits = [
unit: '1611023124',
delDomain: 'PUBLISHER-d.openx.net',
video: {
- mimes: ['video/x-ms-wmv, video/mp4']
+ mimes: ['video/x-ms-wmv, video/mp4'] // mediaTypes.video preferred
}
}
- }]
+ }]p
}
];
```
diff --git a/modules/openxOrtbBidAdapter.md b/modules/openxOrtbBidAdapter.md
index 04ed32608cb..b5e1820021a 100644
--- a/modules/openxOrtbBidAdapter.md
+++ b/modules/openxOrtbBidAdapter.md
@@ -1,15 +1,17 @@
# Overview
```
-Module Name: OpenX OpenRTB Bidder Adapter
+Module Name: OpenX Bidder Adapter
Module Type: Bidder Adapter
Maintainer: team-openx@openx.com
```
# Description
+DEPRECATED. Use openxBidAdapter.
-This is an updated version of the OpenX bid adapter which calls our new serving architecture.
-Publishers are welcome to test this adapter and give feedback. Please note you should only include either openxBidAdapter or openxOrtbBidAdapter in your build.
+This adapter was originally an adapter used to test OpenX serving architecture changes.
+This adapter now mirrors openxBidAdapter and this adapter will be removed in a future release. Please use openxBidAdapter.
+Please note you should only include either openxBidAdapter or openxOrtbBidAdapter in your build.
# Bid Parameters
## Banner
diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js
index 8fe220aa202..d8ea79ac698 100644
--- a/test/spec/modules/openxBidAdapter_spec.js
+++ b/test/spec/modules/openxBidAdapter_spec.js
@@ -1,204 +1,81 @@
import {expect} from 'chai';
-import {spec, USER_ID_CODE_TO_QUERY_ARG} from 'modules/openxBidAdapter.js';
+import {spec, REQUEST_URL, SYNC_URL, DEFAULT_PH} from 'modules/openxOrtbBidAdapter.js';
import {newBidder} from 'src/adapters/bidderFactory.js';
import {BANNER, VIDEO} from 'src/mediaTypes.js';
-import {userSync} from 'src/userSync.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
+// load modules that register ORTB processors
+import 'src/prebid.js'
+import 'modules/currency.js';
+import 'modules/userId/index.js';
+import 'modules/multibid/index.js';
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
+import 'modules/schain.js';
+import {deepClone} from 'src/utils.js';
+import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
+import {hook} from '../../../src/hook.js';
+
+const DEFAULT_SYNC = SYNC_URL + '?ph=' + DEFAULT_PH;
+
+const BidRequestBuilder = function BidRequestBuilder(options) {
+ const defaults = {
+ request: {
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
+ adUnitCode: 'adunit-code',
+ bidder: 'openx'
+ },
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ sizes: [[300, 250], [300, 600]],
+ };
-const URLBASE = '/w/1.0/arj';
-const URLBASEVIDEO = '/v/1.0/avjp';
-
-describe('OpenxAdapter', function () {
- const adapter = newBidder(spec);
-
- /**
- * Type Definitions
- */
-
- /**
- * @typedef {{
- * impression: string,
- * inview: string,
- * click: string
- * }}
- */
- let OxArjTracking;
- /**
- * @typedef {{
- * ads: {
- * version: number,
- * count: number,
- * pixels: string,
- * ad: Array
- * }
- * }}
- */
- let OxArjResponse;
- /**
- * @typedef {{
- * adunitid: number,
- * adid:number,
- * type: string,
- * htmlz: string,
- * framed: number,
- * is_fallback: number,
- * ts: string,
- * cpipc: number,
- * pub_rev: string,
- * tbd: ?string,
- * adv_id: string,
- * deal_id: string,
- * auct_win_is_deal: number,
- * brand_id: string,
- * currency: string,
- * idx: string,
- * creative: Array
- * }}
- */
- let OxArjAdUnit;
- /**
- * @typedef {{
- * id: string,
- * width: string,
- * height: string,
- * target: string,
- * mime: string,
- * media: string,
- * tracking: OxArjTracking
- * }}
- */
- let OxArjCreative;
-
- // HELPER METHODS
- /**
- * @type {OxArjCreative}
- */
- const DEFAULT_TEST_ARJ_CREATIVE = {
- id: '0',
- width: 'test-width',
- height: 'test-height',
- target: 'test-target',
- mime: 'test-mime',
- media: 'test-media',
- tracking: {
- impression: 'test-impression',
- inview: 'test-inview',
- click: 'test-click'
- }
+ const request = {
+ ...defaults.request,
+ ...options
};
- /**
- * @type {OxArjAdUnit}
- */
- const DEFAULT_TEST_ARJ_AD_UNIT = {
- adunitid: 0,
- type: 'test-type',
- html: 'test-html',
- framed: 0,
- is_fallback: 0,
- ts: 'test-ts',
- tbd: 'NaN',
- deal_id: undefined,
- auct_win_is_deal: undefined,
- cpipc: 0,
- pub_rev: 'test-pub_rev',
- adv_id: 'test-adv_id',
- brand_id: 'test-brand_id',
- currency: 'test-currency',
- idx: '0',
- creative: [DEFAULT_TEST_ARJ_CREATIVE]
+ this.withParams = (options) => {
+ request.params = {
+ ...defaults.params,
+ ...options
+ };
+ return this;
};
- /**
- * @type {OxArjResponse}
- */
- const DEFAULT_ARJ_RESPONSE = {
- ads: {
- version: 0,
- count: 1,
- pixels: 'https://testpixels.net',
- ad: [DEFAULT_TEST_ARJ_AD_UNIT]
+ this.build = () => request;
+};
+
+const BidderRequestBuilder = function BidderRequestBuilder(options) {
+ const defaults = {
+ bidderCode: 'openx',
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
+ bidderRequestId: '7g36s867Tr4xF90X',
+ timeout: 3000,
+ refererInfo: {
+ numIframes: 0,
+ reachedTop: true,
+ referer: 'http://test.io/index.html?pbjs_debug=true'
}
};
- // Sample bid requests
+ const request = {
+ ...defaults,
+ ...options
+ };
- const BANNER_BID_REQUESTS_WITH_MEDIA_TYPES = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain'
- },
- adUnitCode: '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1',
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2',
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-1' } } },
- }];
-
- const VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES = [{
- bidder: 'openx',
- mediaTypes: {
- video: {
- playerSize: [640, 480]
- }
- },
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
+ this.build = () => request;
+};
- bidId: '30b31c1838de1e',
- bidderRequestId: '22edbae2733bf6',
- auctionId: '1d1a030790a475',
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
- }];
+describe('OpenxRtbAdapter', function () {
+ before(() => {
+ hook.ready();
+ });
- const MULTI_FORMAT_BID_REQUESTS = [{
- bidder: 'openx',
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250]]
- },
- video: {
- playerSize: [300, 250]
- }
- },
- bidId: '30b31c1838de1e',
- bidderRequestId: '22edbae2733bf6',
- auctionId: '1d1a030790a475',
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e',
- ortb2Imp: { ext: { data: { pbadslot: '/12345/my-gpt-tag-0' } } },
- }];
+ const adapter = newBidder(spec);
describe('inherited functions', function () {
it('exists and is a function', function () {
@@ -206,7 +83,7 @@ describe('OpenxAdapter', function () {
});
});
- describe('isBidRequestValid', function () {
+ describe('isBidRequestValid()', function () {
describe('when request is for a banner ad', function () {
let bannerBid;
beforeEach(function () {
@@ -259,8 +136,28 @@ describe('OpenxAdapter', function () {
describe('when request is for a multiformat ad', function () {
describe('and request config uses mediaTypes video and banner', () => {
+ const multiformatBid = {
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ },
+ video: {
+ playerSize: [300, 250]
+ }
+ },
+ bidId: '30b31c1838de1e',
+ bidderRequestId: '22edbae2733bf6',
+ auctionId: '1d1a030790a475',
+ transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
+ };
it('should return true multisize when required params found', function () {
- expect(spec.isBidRequestValid(MULTI_FORMAT_BID_REQUESTS[0])).to.equal(true);
+ expect(spec.isBidRequestValid(multiformatBid)).to.equal(true);
});
});
});
@@ -349,1509 +246,1035 @@ describe('OpenxAdapter', function () {
expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(false);
});
});
-
- describe('and request config uses test', () => {
- const videoBidWithTest = {
- bidder: 'openx',
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain',
- test: true
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- video: {
- playerSize: [640, 480]
- }
- },
- bidId: '30b31c1838de1e',
- bidderRequestId: '22edbae2733bf6',
- auctionId: '1d1a030790a475',
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
- };
-
- let mockBidderRequest = {refererInfo: {}};
-
- it('should return true when required params found', function () {
- expect(spec.isBidRequestValid(videoBidWithTest)).to.equal(true);
- });
-
- it('should send video bid request to openx url via GET, with vtest=1 video parameter', function () {
- const request = spec.buildRequests([videoBidWithTest], mockBidderRequest);
- expect(request[0].data.vtest).to.equal(1);
- });
- });
});
});
- describe('buildRequests for banner ads', function () {
- const bidRequestsWithMediaTypes = BANNER_BID_REQUESTS_WITH_MEDIA_TYPES;
-
- const bidRequestsWithPlatform = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '11',
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
- },
- 'adUnitCode': '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
- }, {
- 'bidder': 'openx',
- 'params': {
- 'unit': '11',
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
- },
- 'adUnitCode': '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
- }];
-
- const mockBidderRequest = {refererInfo: {}};
-
- it('should send bid request to openx url via GET, with mediaTypes specified with banner type', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASE);
- expect(request[0].data.ph).to.be.undefined;
- expect(request[0].method).to.equal('GET');
- });
-
- it('should send bid request to openx platform url via GET, if platform is present', function () {
- const request = spec.buildRequests(bidRequestsWithPlatform, mockBidderRequest);
- expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
- expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
- expect(request[0].method).to.equal('GET');
- });
-
- it('should send bid request to openx platform url via GET, if both params present', function () {
- const bidRequestsWithPlatformAndDelDomain = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '11',
- 'delDomain': 'test-del-domain',
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
- },
- 'adUnitCode': '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
- }, {
- 'bidder': 'openx',
- 'params': {
- 'unit': '11',
- 'delDomain': 'test-del-domain',
- 'platform': '1cabba9e-cafe-3665-beef-f00f00f00f00'
- },
- 'adUnitCode': '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
- }];
-
- const request = spec.buildRequests(bidRequestsWithPlatformAndDelDomain, mockBidderRequest);
- expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`);
- expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform);
- expect(request[0].method).to.equal('GET');
- });
+ describe('buildRequests()', function () {
+ let bidRequestsWithMediaTypes;
+ let bidRequestsWithPlatform;
+ let mockBidderRequest;
- it('should send the adunit codes', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].data.divids).to.equal(`${encodeURIComponent(bidRequestsWithMediaTypes[0].adUnitCode)},${encodeURIComponent(bidRequestsWithMediaTypes[1].adUnitCode)}`);
- });
-
- it('should send the gpids', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].data.aucs).to.equal(`${encodeURIComponent('/12345/my-gpt-tag-0')},${encodeURIComponent('/12345/my-gpt-tag-1')}`);
- });
+ beforeEach(function () {
+ mockBidderRequest = {refererInfo: {}};
- it('should send ad unit ids when any are defined', function () {
- const bidRequestsWithUnitIds = [{
- 'bidder': 'openx',
- 'params': {
- 'delDomain': 'test-del-domain'
+ bidRequestsWithMediaTypes = [{
+ bidder: 'openx',
+ params: {
+ unit: '11',
+ delDomain: 'test-del-domain',
+ platform: '1cabba9e-cafe-3665-beef-f00f00f00f00',
},
- 'adUnitCode': 'adunit-code',
+ adUnitCode: '/adunit-code/test-path',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
- }, {
- 'bidder': 'openx',
- 'params': {
- 'unit': '22',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- 'bidId': 'test-bid-id-2',
- 'bidderRequestId': 'test-bid-request-2',
- 'auctionId': 'test-auction-2'
- }];
- const request = spec.buildRequests(bidRequestsWithUnitIds, mockBidderRequest);
- expect(request[0].data.auid).to.equal(`,${bidRequestsWithUnitIds[1].params.unit}`);
- });
-
- it('should not send any ad unit ids when none are defined', function () {
- const bidRequestsWithoutUnitIds = [{
- 'bidder': 'openx',
- 'params': {
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ ortb2Imp: {
+ ext: {
+ ae: 2
}
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
+ }
}, {
- 'bidder': 'openx',
- 'params': {
- 'delDomain': 'test-del-domain'
+ bidder: 'openx',
+ params: {
+ unit: '22',
+ delDomain: 'test-del-domain',
+ platform: '1cabba9e-cafe-3665-beef-f00f00f00f00',
},
- 'adUnitCode': 'adunit-code',
+ adUnitCode: 'adunit-code',
mediaTypes: {
- banner: {
- sizes: [[728, 90]]
+ video: {
+ playerSize: [640, 480]
}
},
- 'bidId': 'test-bid-id-2',
- 'bidderRequestId': 'test-bid-request-2',
- 'auctionId': 'test-auction-2'
+ bidId: 'test-bid-id-2',
+ bidderRequestId: 'test-bid-request-2',
+ auctionId: 'test-auction-2',
+ transactionId: 'test-transactionId-2'
}];
- const request = spec.buildRequests(bidRequestsWithoutUnitIds, mockBidderRequest);
- expect(request[0].data).to.not.have.any.keys('auid');
});
- it('should send out custom params on bids that have customParams specified', function () {
- const bidRequest = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- params: {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain',
- 'customParams': {'Test1': 'testval1+', 'test2': ['testval2/', 'testval3']}
- }
+ context('common requests checks', function() {
+ it('should be able to handle multiformat requests', () => {
+ const multiformat = utils.deepClone(bidRequestsWithMediaTypes[0]);
+ multiformat.mediaTypes.video = {
+ context: 'outstream',
+ playerSize: [640, 480]
}
- );
+ const requests = spec.buildRequests([multiformat], mockBidderRequest);
+ const outgoingFormats = requests.flatMap(rq => rq.data.imp.flatMap(imp => ['banner', 'video'].filter(k => imp[k] != null)));
+ const expected = FEATURES.VIDEO ? ['banner', 'video'] : ['banner']
+ expect(outgoingFormats).to.have.members(expected);
+ })
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
- const dataParams = request[0].data;
+ it('should send bid request to openx url via POST', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].url).to.equal(REQUEST_URL);
+ expect(request[0].method).to.equal('POST');
+ });
- expect(dataParams.tps).to.exist;
- expect(dataParams.tps).to.equal(btoa('test1=testval1.&test2=testval2_,testval3'));
- });
+ it('should send delivery domain, if available', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].data.ext.delDomain).to.equal(bidRequestsWithMediaTypes[0].params.delDomain);
+ expect(request[0].data.ext.platformId).to.be.undefined;
+ });
- it('should send out custom bc parameter, if override is present', function () {
- const bidRequest = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- params: {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain',
- 'bc': 'hb_override'
- }
- }
- );
+ it('should send platform id, if available', function () {
+ bidRequestsWithMediaTypes[0].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00';
+ bidRequestsWithMediaTypes[1].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00';
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
- const dataParams = request[0].data;
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform);
+ expect(request[1].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform);
+ });
- expect(dataParams.bc).to.exist;
- expect(dataParams.bc).to.equal('hb_override');
- });
+ it('should send openx adunit codes', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[0].params.unit);
+ expect(request[1].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit);
+ });
- it('should not send any consent management properties', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].data.gdpr).to.equal(undefined);
- expect(request[0].data.gdpr_consent).to.equal(undefined);
- expect(request[0].data.x_gdpr_f).to.equal(undefined);
- });
+ it('should send out custom params on bids that have customParams specified', function () {
+ const bidRequest = Object.assign({},
+ bidRequestsWithMediaTypes[0],
+ {
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain',
+ customParams: {'Test1': 'testval1+', 'test2': ['testval2/', 'testval3']}
+ }
+ }
+ );
- describe('when there is a consent management framework', function () {
- let bidRequests;
- let mockConfig;
- let bidderRequest;
- const IAB_CONSENT_FRAMEWORK_CODE = 1;
+ mockBidderRequest.bids = [bidRequest];
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
+ expect(request[0].data.imp[0].ext.customParams).to.equal(bidRequest.params.customParams);
+ })
- beforeEach(function () {
- bidRequests = [{
- bidder: 'openx',
- params: {
- unit: '12345678-banner',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id',
- bidderRequestId: 'test-bidder-request-id',
- auctionId: 'test-auction-id'
- }, {
- 'bidder': 'openx',
- 'mediaTypes': {
- video: {
- playerSize: [640, 480]
+ describe('floors', function () {
+ it('should send out custom floors on bids that have customFloors, no currency as account currency is used', function () {
+ const bidRequest = Object.assign({},
+ bidRequestsWithMediaTypes[0],
+ {
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain',
+ customFloor: 1.500
+ }
}
- },
- 'params': {
- 'unit': '12345678-video',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
+ );
- bidId: 'test-bid-id',
- bidderRequestId: 'test-bidder-request-id',
- auctionId: 'test-auction-id',
- transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
- }];
- });
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
+ expect(request[0].data.imp[0].bidfloor).to.equal(bidRequest.params.customFloor);
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined);
+ });
- afterEach(function () {
- config.getConfig.restore();
- });
+ context('with floors module', function () {
+ let adServerCurrencyStub;
- describe('when us_privacy applies', function () {
- beforeEach(function () {
- bidderRequest = {
- uspConsent: '1YYN',
- refererInfo: {}
- };
+ beforeEach(function () {
+ adServerCurrencyStub = sinon
+ .stub(config, 'getConfig')
+ .withArgs('currency.adServerCurrency')
+ });
- sinon.stub(config, 'getConfig').callsFake((key) => {
- return utils.deepAccess(mockConfig, key);
+ afterEach(function () {
+ config.getConfig.restore();
});
- });
- it('should send a signal to specify that GDPR applies to this request', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.us_privacy).to.equal('1YYN');
- expect(request[1].data.us_privacy).to.equal('1YYN');
- });
- });
+ it('should send out floors on bids in USD', function () {
+ const bidRequest = Object.assign({},
+ bidRequestsWithMediaTypes[0],
+ {
+ getFloor: () => {
+ return {
+ currency: 'USD',
+ floor: 9.99
+ }
+ }
+ }
+ );
- describe('when us_privacy does not applies', function () {
- beforeEach(function () {
- bidderRequest = {
- refererInfo: {}
- };
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
+ expect(request[0].data.imp[0].bidfloor).to.equal(9.99);
+ expect(request[0].data.imp[0].bidfloorcur).to.equal('USD');
+ });
- sinon.stub(config, 'getConfig').callsFake((key) => {
- return utils.deepAccess(mockConfig, key);
+ it('should send not send floors', function () {
+ adServerCurrencyStub.returns('EUR');
+ const bidRequest = Object.assign({},
+ bidRequestsWithMediaTypes[0],
+ {
+ getFloor: () => {
+ return {
+ currency: 'BTC',
+ floor: 9.99
+ }
+ }
+ }
+ );
+
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
+ expect(request[0].data.imp[0].bidfloor).to.equal(undefined)
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined)
});
- });
+ })
+ })
- it('should not send the consent string, when consent string is undefined', function () {
- delete bidderRequest.uspConsent;
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data).to.not.have.property('us_privacy');
- expect(request[1].data).to.not.have.property('us_privacy');
- });
- });
+ describe('FPD', function() {
+ let bidRequests;
+ const mockBidderRequest = {refererInfo: {}};
- describe('when GDPR applies', function () {
beforeEach(function () {
- bidderRequest = {
- gdprConsent: {
- consentString: 'test-gdpr-consent-string',
- gdprApplies: true
+ bidRequests = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678-banner',
+ delDomain: 'test-del-domain'
},
- refererInfo: {}
- };
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]]
+ }
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id',
+ transactionId: 'test-transaction-id-1'
+ }, {
+ bidder: 'openx',
+ mediaTypes: {
+ video: {
+ playerSize: [640, 480]
+ }
+ },
+ params: {
+ unit: '12345678-video',
+ delDomain: 'test-del-domain'
+ },
+ 'adUnitCode': 'adunit-code',
- mockConfig = {
- consentManagement: {
- cmpApi: 'iab',
- timeout: 1111,
- allowAuctionWithoutConsent: 'cancel'
- }
- };
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id',
+ transactionId: 'test-transaction-id-2'
+ }];
+ });
- sinon.stub(config, 'getConfig').callsFake((key) => {
- return utils.deepAccess(mockConfig, key);
+ it('ortb2.site should be merged in the request', function() {
+ const request = spec.buildRequests(bidRequests, {
+ ...mockBidderRequest,
+ 'ortb2': {
+ site: {
+ domain: 'page.example.com',
+ cat: ['IAB2'],
+ sectioncat: ['IAB2-2']
+ }
+ }
});
+ let data = request[0].data;
+ expect(data.site.domain).to.equal('page.example.com');
+ expect(data.site.cat).to.deep.equal(['IAB2']);
+ expect(data.site.sectioncat).to.deep.equal(['IAB2-2']);
});
- it('should send a signal to specify that GDPR applies to this request', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.gdpr).to.equal(1);
- expect(request[1].data.gdpr).to.equal(1);
+ it('ortb2.user should be merged in the request', function() {
+ const request = spec.buildRequests(bidRequests, {
+ ...mockBidderRequest,
+ 'ortb2': {
+ user: {
+ yob: 1985
+ }
+ }
+ });
+ let data = request[0].data;
+ expect(data.user.yob).to.equal(1985);
});
- it('should send the consent string', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
- expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
- });
+ describe('ortb2Imp', function() {
+ describe('ortb2Imp.ext.data.pbadslot', function() {
+ beforeEach(function () {
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
+ delete bidRequests[0].ortb2Imp;
+ }
+ });
- it('should send the consent management framework code', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
- expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
- });
- });
+ it('should not send if imp[].ext.data object is invalid', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {}
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext).to.not.have.property('data');
+ });
- describe('when GDPR does not apply', function () {
- beforeEach(function () {
- bidderRequest = {
- gdprConsent: {
- consentString: 'test-gdpr-consent-string',
- gdprApplies: false
- },
- refererInfo: {}
- };
-
- mockConfig = {
- consentManagement: {
- cmpApi: 'iab',
- timeout: 1111,
- allowAuctionWithoutConsent: 'cancel'
- }
- };
+ it('should not send if imp[].ext.data.pbadslot is undefined', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ if (data.imp[0].ext.data) {
+ expect(data.imp[0].ext.data).to.not.have.property('pbadslot');
+ } else {
+ expect(data.imp[0].ext).to.not.have.property('data');
+ }
+ });
- sinon.stub(config, 'getConfig').callsFake((key) => {
- return utils.deepAccess(mockConfig, key);
+ it('should send if imp[].ext.data.pbadslot is string', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ pbadslot: 'abcd'
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext.data).to.have.property('pbadslot');
+ expect(data.imp[0].ext.data.pbadslot).to.equal('abcd');
+ });
});
- });
- it('should not send a signal to specify that GDPR does not apply to this request', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.gdpr).to.equal(0);
- expect(request[1].data.gdpr).to.equal(0);
- });
+ describe('ortb2Imp.ext.data.adserver', function() {
+ beforeEach(function () {
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
+ delete bidRequests[0].ortb2Imp;
+ }
+ });
- it('should send the consent string', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
- expect(request[1].data.gdpr_consent).to.equal(bidderRequest.gdprConsent.consentString);
- });
+ it('should not send if imp[].ext.data object is invalid', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {}
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext).to.not.have.property('data');
+ });
- it('should send the consent management framework code', function () {
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
- expect(request[1].data.x_gdpr_f).to.equal(IAB_CONSENT_FRAMEWORK_CODE);
- });
- });
+ it('should not send if imp[].ext.data.adserver is undefined', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ if (data.imp[0].ext.data) {
+ expect(data.imp[0].ext.data).to.not.have.property('adserver');
+ } else {
+ expect(data.imp[0].ext).to.not.have.property('data');
+ }
+ });
- describe('when GDPR consent has undefined data', function () {
- beforeEach(function () {
- bidderRequest = {
- gdprConsent: {
- consentString: 'test-gdpr-consent-string',
- gdprApplies: true
- },
- refererInfo: {}
- };
+ it('should send', function() {
+ let adSlotValue = 'abc';
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ adserver: {
+ name: 'GAM',
+ adslot: adSlotValue
+ }
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext.data.adserver.name).to.equal('GAM');
+ expect(data.imp[0].ext.data.adserver.adslot).to.equal(adSlotValue);
+ });
+ });
- mockConfig = {
- consentManagement: {
- cmpApi: 'iab',
- timeout: 1111,
- allowAuctionWithoutConsent: 'cancel'
- }
- };
+ describe('ortb2Imp.ext.data.other', function() {
+ beforeEach(function () {
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
+ delete bidRequests[0].ortb2Imp;
+ }
+ });
- sinon.stub(config, 'getConfig').callsFake((key) => {
- return utils.deepAccess(mockConfig, key);
- });
- });
+ it('should not send if imp[].ext.data object is invalid', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {}
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext).to.not.have.property('data');
+ });
- it('should not send a signal to specify whether GDPR applies to this request, when GDPR application is undefined', function () {
- delete bidderRequest.gdprConsent.gdprApplies;
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data).to.not.have.property('gdpr');
- expect(request[1].data).to.not.have.property('gdpr');
- });
+ it('should not send if imp[].ext.data.other is undefined', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ if (data.imp[0].ext.data) {
+ expect(data.imp[0].ext.data).to.not.have.property('other');
+ } else {
+ expect(data.imp[0].ext).to.not.have.property('data');
+ }
+ });
- it('should not send the consent string, when consent string is undefined', function () {
- delete bidderRequest.gdprConsent.consentString;
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data).to.not.have.property('gdpr_consent');
- expect(request[1].data).to.not.have.property('gdpr_consent');
+ it('ortb2Imp.ext.data.other', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ data: {
+ other: 1234
+ }
+ }
+ };
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ let data = request[0].data;
+ expect(data.imp[0].ext.data.other).to.equal(1234);
+ });
+ });
});
- it('should not send the consent management framework code, when format is undefined', function () {
- delete mockConfig.consentManagement.cmpApi;
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request[0].data).to.not.have.property('x_gdpr_f');
- expect(request[1].data).to.not.have.property('x_gdpr_f');
+ describe('with user agent client hints', function () {
+ it('should add device.sua if available', function () {
+ const bidderRequestWithUserAgentClientHints = { refererInfo: {},
+ ortb2: {
+ device: {
+ sua: {
+ source: 2,
+ platform: {
+ brand: 'macOS',
+ version: [ '12', '4', '0' ]
+ },
+ browsers: [
+ {
+ brand: 'Chromium',
+ version: [ '106', '0', '5249', '119' ]
+ },
+ {
+ brand: 'Google Chrome',
+ version: [ '106', '0', '5249', '119' ]
+ },
+ {
+ brand: 'Not;A=Brand',
+ version: [ '99', '0', '0', '0' ]
+ }],
+ mobile: 0,
+ model: 'Pro',
+ bitness: '64',
+ architecture: 'x86'
+ }
+ }
+ }};
+
+ let request = spec.buildRequests(bidRequests, bidderRequestWithUserAgentClientHints);
+ expect(request[0].data.device.sua).to.exist;
+ expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua);
+ const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}};
+ request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints);
+ expect(request[0].data.device?.sua).to.not.exist;
+ });
});
});
- });
-
- it('should not send a coppa query param when there are no coppa param settings in the bid requests', function () {
- const bidRequestsWithoutCoppa = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain',
- coppa: false
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2'
- }];
- const request = spec.buildRequests(bidRequestsWithoutCoppa, mockBidderRequest);
- expect(request[0].data).to.not.have.any.keys('tfcd');
- });
-
- it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
- const bidRequestsWithCoppa = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain',
- coppa: false
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain',
- coppa: true
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2'
- }];
- const request = spec.buildRequests(bidRequestsWithCoppa, mockBidderRequest);
- expect(request[0].data.tfcd).to.equal(1);
- });
- it('should not send a "no segmentation" flag there no DoNotTrack setting that is set to true', function () {
- const bidRequestsWithoutDnt = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain',
- doNotTrack: false
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2'
- }];
- const request = spec.buildRequests(bidRequestsWithoutDnt, mockBidderRequest);
- expect(request[0].data).to.not.have.any.keys('ns');
- });
+ context('when there is a consent management framework', function () {
+ let bidRequests;
+ let mockConfig;
+ let bidderRequest;
- it('should send a "no segmentation" flag there is any DoNotTrack setting that is set to true', function () {
- const bidRequestsWithDnt = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain',
- doNotTrack: false
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain',
- doNotTrack: true
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2'
- }];
- const request = spec.buildRequests(bidRequestsWithDnt, mockBidderRequest);
- expect(request[0].data.ns).to.equal(1);
- });
-
- describe('when schain is provided', function () {
- let bidRequests;
- let schainConfig;
- const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
-
- beforeEach(function () {
- schainConfig = {
- 'ver': '1.0',
- 'complete': 1,
- 'nodes': [
- {
- 'asi': 'exchange1.com',
- 'sid': '1234',
- 'hp': 1,
- 'rid': 'bid-request-1',
- 'name': 'publisher',
- 'domain': 'publisher.com'
- // omitted ext
+ beforeEach(function () {
+ bidRequests = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678-banner',
+ delDomain: 'test-del-domain'
},
- {
- 'asi': 'exchange2.com',
- 'sid': 'abcd',
- 'hp': 1,
- 'rid': 'bid-request-2',
- // name field missing
- 'domain': 'intermediary.com'
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]]
+ }
},
- {
- 'asi': 'exchange3.com',
- 'sid': '4321',
- 'hp': 1,
- // request id
- // name field missing
- 'domain': 'intermediary-2.com'
- }
- ]
- };
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id',
+ transactionId: 'test-transaction-id-1'
+ }, {
+ bidder: 'openx',
+ mediaTypes: {
+ video: {
+ playerSize: [640, 480]
+ }
+ },
+ params: {
+ unit: '12345678-video',
+ delDomain: 'test-del-domain'
+ },
+ 'adUnitCode': 'adunit-code',
- bidRequests = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '11',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': '/adunit-code/test-path',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1',
- 'schain': schainConfig
- }];
- });
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id',
+ transactionId: 'test-transaction-id-2'
+ }];
+ });
- it('should send a schain parameter with the proper delimiter symbols', function () {
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
- const dataParams = request[0].data;
- const numNodes = schainConfig.nodes.length;
+ describe('us_privacy', function () {
+ beforeEach(function () {
+ bidderRequest = {
+ uspConsent: '1YYN',
+ refererInfo: {}
+ };
- // each node will have a ! to denote beginning of a new node
- expect(dataParams.schain.match(/!/g).length).to.equal(numNodes);
+ sinon.stub(config, 'getConfig').callsFake((key) => {
+ return utils.deepAccess(mockConfig, key);
+ });
+ });
- // 1 comma in the front for version
- // 5 commas per node
- expect(dataParams.schain.match(/,/g).length).to.equal(numNodes * 5 + 1);
- });
+ afterEach(function () {
+ config.getConfig.restore();
+ });
- it('should send a schain with the right version', function () {
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
- const dataParams = request[0].data;
- let serializedSupplyChain = dataParams.schain.split('!');
- let version = serializedSupplyChain.shift().split(',')[0];
+ it('should send a signal to specify that US Privacy applies to this request', function () {
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN');
+ expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN');
+ });
- expect(version).to.equal(bidRequests[0].schain.ver);
- });
+ it('should not send the regs object, when consent string is undefined', function () {
+ delete bidderRequest.uspConsent;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.regs?.us_privacy).to.not.exist;
+ });
+ });
- it('should send a schain with the right complete value', function () {
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
- const dataParams = request[0].data;
- let serializedSupplyChain = dataParams.schain.split('!');
- let isComplete = serializedSupplyChain.shift().split(',')[1];
+ describe('GDPR', function () {
+ beforeEach(function () {
+ bidderRequest = {
+ gdprConsent: {
+ consentString: 'test-gdpr-consent-string',
+ addtlConsent: 'test-addtl-consent-string',
+ gdprApplies: true
+ },
+ refererInfo: {}
+ };
+
+ mockConfig = {
+ consentManagement: {
+ cmpApi: 'iab',
+ timeout: 1111,
+ allowAuctionWithoutConsent: 'cancel'
+ }
+ };
- expect(isComplete).to.equal(String(bidRequests[0].schain.complete));
- });
+ sinon.stub(config, 'getConfig').callsFake((key) => {
+ return utils.deepAccess(mockConfig, key);
+ });
+ });
- it('should send all available params in the right order', function () {
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
- const dataParams = request[0].data;
- let serializedSupplyChain = dataParams.schain.split('!');
- serializedSupplyChain.shift();
+ afterEach(function () {
+ config.getConfig.restore();
+ });
- serializedSupplyChain.forEach((serializedNode, nodeIndex) => {
- let nodeProperties = serializedNode.split(',');
+ it('should send a signal to specify that GDPR applies to this request', function () {
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.regs.ext.gdpr).to.equal(1);
+ expect(request[1].data.regs.ext.gdpr).to.equal(1);
+ });
- nodeProperties.forEach((nodeProperty, propertyIndex) => {
- let node = schainConfig.nodes[nodeIndex];
- let key = supplyChainNodePropertyOrder[propertyIndex];
+ it('should send the consent string', function () {
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
+ });
- expect(nodeProperty).to.equal(node[key] ? String(node[key]) : '',
- `expected node '${nodeIndex}' property '${nodeProperty}' to key '${key}' to be the same value`)
+ it('should send the addtlConsent string', function () {
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
+ expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
});
- });
- });
- });
- describe('when there are userid providers', function () {
- const EXAMPLE_DATA_BY_ATTR = {
- britepoolid: '1111-britepoolid',
- criteoId: '1111-criteoId',
- fabrickId: '1111-fabrickid',
- haloId: '1111-haloid',
- id5id: {uid: '1111-id5id'},
- idl_env: '1111-idl_env',
- IDP: '1111-zeotap-idplusid',
- idxId: '1111-idxid',
- intentIqId: '1111-intentiqid',
- lipb: {lipbid: '1111-lipb'},
- lotamePanoramaId: '1111-lotameid',
- merkleId: {id: '1111-merkleid'},
- netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
- parrableId: { eid: 'eidVersion.encryptionKeyReference.encryptedValue' },
- pubcid: '1111-pubcid',
- quantcastId: '1111-quantcastid',
- tapadId: '111-tapadid',
- tdid: '1111-tdid',
- uid2: {id: '1111-uid2'},
- novatiq: {snowflake: '1111-novatiqid'},
- admixerId: '1111-admixerid',
- deepintentId: '1111-deepintentid',
- dmdId: '111-dmdid',
- nextrollId: '1111-nextrollid',
- mwOpenLinkId: '1111-mwopenlinkid',
- dapId: '1111-dapId',
- amxId: '1111-amxid',
- kpuid: '1111-kpuid',
- publinkId: '1111-publinkid',
- naveggId: '1111-naveggid',
- imuid: '1111-imuid',
- adtelligentId: '1111-adtelligentid'
- };
-
- // generates the same set of tests for each id provider
- utils._each(USER_ID_CODE_TO_QUERY_ARG, (userIdQueryArg, userIdProviderKey) => {
- describe(`with userId attribute: ${userIdProviderKey}`, function () {
- it(`should not send a ${userIdQueryArg} query param when there is no userId.${userIdProviderKey} defined in the bid requests`, function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].data).to.not.have.any.keys(userIdQueryArg);
+ it('should send a signal to specify that GDPR does not apply to this request', function () {
+ bidderRequest.gdprConsent.gdprApplies = false;
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.regs.ext.gdpr).to.equal(0);
+ expect(request[1].data.regs.ext.gdpr).to.equal(0);
});
- it(`should send a ${userIdQueryArg} query param when userId.${userIdProviderKey} is defined in the bid requests`, function () {
- const bidRequestsWithUserId = [{
- bidder: 'openx',
- params: {
- unit: '11',
- delDomain: 'test-del-domain'
- },
- userId: {
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1'
- }];
- // enrich bid request with userId key/value
- bidRequestsWithUserId[0].userId[userIdProviderKey] = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
-
- const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
-
- let userIdValue;
- // handle cases where userId key refers to an object
- switch (userIdProviderKey) {
- case 'merkleId':
- userIdValue = EXAMPLE_DATA_BY_ATTR.merkleId.id;
- break;
- case 'uid2':
- userIdValue = EXAMPLE_DATA_BY_ATTR.uid2.id;
- break;
- case 'lipb':
- userIdValue = EXAMPLE_DATA_BY_ATTR.lipb.lipbid;
- break;
- case 'parrableId':
- userIdValue = EXAMPLE_DATA_BY_ATTR.parrableId.eid;
- break;
- case 'id5id':
- userIdValue = EXAMPLE_DATA_BY_ATTR.id5id.uid;
- break;
- case 'novatiq':
- userIdValue = EXAMPLE_DATA_BY_ATTR.novatiq.snowflake;
- break;
- default:
- userIdValue = EXAMPLE_DATA_BY_ATTR[userIdProviderKey];
- }
+ it('when GDPR application is undefined, should not send a signal to specify whether GDPR applies to this request, ' +
+ 'but can send consent data, ', function () {
+ delete bidderRequest.gdprConsent.gdprApplies;
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok;
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
+ });
- expect(request[0].data[USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey]]).to.equal(userIdValue);
+ it('when consent string is undefined, should not send the consent string, ', function () {
+ delete bidderRequest.gdprConsent.consentString;
+ bidderRequest.bids = bidRequests;
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ expect(request[0].data.imp[0].ext.consent).to.equal(undefined);
+ expect(request[1].data.imp[0].ext.consent).to.equal(undefined);
});
});
});
- });
-
- describe('floors', function () {
- it('should send out custom floors on bids that have customFloors specified', function () {
- const bidRequest = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- params: {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain',
- 'customFloor': 1.500001
- }
- }
- );
-
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
- const dataParams = request[0].data;
-
- expect(dataParams.aumfs).to.exist;
- expect(dataParams.aumfs).to.equal('1500');
- });
- context('with floors module', function () {
- let adServerCurrencyStub;
-
- beforeEach(function () {
- adServerCurrencyStub = sinon
- .stub(config, 'getConfig')
- .withArgs('currency.adServerCurrency')
+ context('coppa', function() {
+ it('when there are no coppa param settings, should not send a coppa flag', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ expect(request[0].data.regs?.coppa).to.be.not.ok;
});
- afterEach(function () {
- config.getConfig.restore();
- });
-
- it('should send out floors on bids', function () {
- const bidRequest1 = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- getFloor: () => {
- return {
- currency: 'AUS',
- floor: 9.99
- }
- }
- }
- );
-
- const bidRequest2 = Object.assign({},
- bidRequestsWithMediaTypes[1],
- {
- getFloor: () => {
- return {
- currency: 'AUS',
- floor: 18.881
- }
- }
- }
- );
+ it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
+ let mockConfig = {
+ coppa: true
+ };
- const request = spec.buildRequests([bidRequest1, bidRequest2], mockBidderRequest);
- const dataParams = request[0].data;
+ sinon.stub(config, 'getConfig').callsFake((key) => {
+ return utils.deepAccess(mockConfig, key);
+ });
- expect(dataParams.aumfs).to.exist;
- expect(dataParams.aumfs).to.equal('9990,18881');
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ expect(request[0].data.regs.coppa).to.equal(1);
});
- it('should send out floors on bids in the default currency', function () {
- const bidRequest1 = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- getFloor: () => {
- return {};
- }
- }
- );
-
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
-
- spec.buildRequests([bidRequest1], mockBidderRequest);
- expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
- expect(getFloorSpy.args[0][0].currency).to.equal('USD');
+ it('should send a coppa flag there is when there is coppa param settings in the bid params', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ request.params = {coppa: true};
+ expect(request[0].data.regs.coppa).to.equal(1);
});
- it('should send out floors on bids in the ad server currency if defined', function () {
- adServerCurrencyStub.returns('bitcoin');
-
- const bidRequest1 = Object.assign({},
- bidRequestsWithMediaTypes[0],
- {
- getFloor: () => {
- return {};
- }
- }
- );
-
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
-
- spec.buildRequests([bidRequest1], mockBidderRequest);
- expect(getFloorSpy.args[0][0].mediaType).to.equal(BANNER);
- expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin');
+ after(function () {
+ config.getConfig.restore()
});
- })
- })
- });
-
- describe('buildRequests for video', function () {
- const bidRequestsWithMediaTypes = VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES;
- const mockBidderRequest = {refererInfo: {}};
-
- it('should send bid request to openx url via GET, with mediaTypes having video parameter', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASEVIDEO);
- expect(request[0].method).to.equal('GET');
- });
- it('should have the correct parameters', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- const dataParams = request[0].data;
-
- expect(dataParams.auid).to.equal('12345678');
- expect(dataParams.vht).to.equal(480);
- expect(dataParams.vwd).to.equal(640);
- expect(dataParams.aucs).to.equal(encodeURIComponent('/12345/my-gpt-tag-0'));
- });
-
- it('shouldn\'t have the test parameter', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- expect(request[0].data.vtest).to.be.undefined;
- });
-
- it('should send a bc parameter', function () {
- const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
- const dataParams = request[0].data;
-
- expect(dataParams.bc).to.have.string('hb_pb');
- });
-
- describe('when using the video param', function () {
- let videoBidRequest;
- let mockBidderRequest = {refererInfo: {}};
-
- beforeEach(function () {
- videoBidRequest = {
- 'bidder': 'openx',
- 'mediaTypes': {
- video: {
- context: 'instream',
- playerSize: [640, 480]
- }
- },
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475',
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
- };
- mockBidderRequest = {refererInfo: {}};
- });
-
- it('should not allow you to set a url', function () {
- videoBidRequest.params.video = {
- url: 'test-url'
- };
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
-
- expect(request[0].data.url).to.be.undefined;
- });
-
- it('should not allow you to override the javascript url', function () {
- let myUrl = 'my-url';
- videoBidRequest.params.video = {
- ju: myUrl
- };
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
-
- expect(request[0].data.ju).to.not.equal(myUrl);
});
- describe('when using the openrtb video params', function () {
- it('should parse legacy params.video.openrtb', function () {
- let myOpenRTBObject = {mimes: ['application/javascript']};
- videoBidRequest.params.video = {
- openrtb: myOpenRTBObject
- };
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
+ context('do not track (DNT)', function() {
+ let doNotTrackStub;
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ beforeEach(function () {
+ doNotTrackStub = sinon.stub(utils, 'getDNT');
});
-
- it('should parse legacy params.openrtb', function () {
- let myOpenRTBObject = {mimes: ['application/javascript']};
- videoBidRequest.params.openrtb = myOpenRTBObject;
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
-
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ afterEach(function() {
+ doNotTrackStub.restore();
});
- it('should parse legacy params.video', function () {
- let myOpenRTBObject = {mimes: ['application/javascript']};
- videoBidRequest.params.video = myOpenRTBObject;
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
+ it('when there is a do not track, should send a dnt', function () {
+ doNotTrackStub.returns(1);
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ expect(request[0].data.device.dnt).to.equal(1);
});
- it('should parse legacy params.video as full openrtb', function () {
- let myOpenRTBObject = {imp: [{video: {mimes: ['application/javascript']}}]};
- videoBidRequest.params.video = myOpenRTBObject;
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
+ it('when there is not do not track, don\'t send dnt', function () {
+ doNotTrackStub.returns(0);
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ expect(request[0].data.device.dnt).to.equal(0);
});
- it('should parse legacy video.openrtb', function () {
- let myOpenRTBObject = {mimes: ['application/javascript']};
- videoBidRequest.params.video = {
- openrtb: myOpenRTBObject
- };
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
+ it('when there is no defined do not track, don\'t send dnt', function () {
+ doNotTrackStub.returns(null);
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
+ expect(request[0].data.device.dnt).to.equal(0);
});
+ });
- it('should omit filtered values for legacy', function () {
- let myOpenRTBObject = {mimes: ['application/javascript'], dont: 'use'};
- videoBidRequest.params.video = {
- openrtb: myOpenRTBObject
+ context('supply chain (schain)', function () {
+ let bidRequests;
+ let schainConfig;
+ const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
+
+ beforeEach(function () {
+ schainConfig = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [
+ {
+ asi: 'exchange1.com',
+ sid: '1234',
+ hp: 1,
+ rid: 'bid-request-1',
+ name: 'publisher',
+ domain: 'publisher.com'
+ // omitted ext
+ },
+ {
+ asi: 'exchange2.com',
+ sid: 'abcd',
+ hp: 1,
+ rid: 'bid-request-2',
+ // name field missing
+ domain: 'intermediary.com'
+ },
+ {
+ asi: 'exchange3.com',
+ sid: '4321',
+ hp: 1,
+ // request id
+ // name field missing
+ domain: 'intermediary-2.com'
+ }
+ ]
};
- const expected = {imp: [{video: {w: 640, h: 480, mimes: ['application/javascript']}}]}
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
- expect(request[0].data.openrtb).to.equal(JSON.stringify(expected));
+ bidRequests = [{
+ bidder: 'openx',
+ params: {
+ unit: '11',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: '/adunit-code/test-path',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]]
+ }
+ },
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ schain: schainConfig
+ }];
});
- it('should parse mediatypes.video', function () {
- videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
- videoBidRequest.mediaTypes.video.minduration = 15
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
- expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
- expect(openRtbRequestParams.imp[0].video.minduration).to.equal(15);
+ it('should send a supply chain object', function () {
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ expect(request[0].data.source.ext.schain).to.equal(schainConfig);
});
- it('should filter mediatypes.video', function () {
- videoBidRequest.mediaTypes.video.mimes = ['application/javascript']
- videoBidRequest.mediaTypes.video.minnothing = 15
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
- expect(openRtbRequestParams.imp[0].video.mimes).to.eql(['application/javascript']);
- expect(openRtbRequestParams.imp[0].video.minnothing).to.equal(undefined);
+ it('should send the supply chain object with the right version', function () {
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ expect(request[0].data.source.ext.schain.ver).to.equal(schainConfig.ver);
});
- it("should use the bidRequest's playerSize", function () {
- const width = 200;
- const height = 100;
- const myOpenRTBObject = {v: height, w: width};
- videoBidRequest.params.video = {
- openrtb: myOpenRTBObject
- };
- const request = spec.buildRequests([videoBidRequest], mockBidderRequest);
- const openRtbRequestParams = JSON.parse(request[0].data.openrtb);
-
- expect(openRtbRequestParams.imp[0].video.w).to.equal(640);
- expect(openRtbRequestParams.imp[0].video.h).to.equal(480);
+ it('should send the supply chain object with the right complete value', function () {
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
+ expect(request[0].data.source.ext.schain.complete).to.equal(schainConfig.complete);
});
});
- });
- describe('floors', function () {
- it('should send out custom floors on bids that have customFloors specified', function () {
- const bidRequest = Object.assign({},
- bidRequestsWithMediaTypes[0],
+ context('when there are userid providers', function () {
+ const userIdAsEids = [
{
- params: {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain',
- 'customFloor': 1.500001
- }
+ source: 'adserver.org',
+ uids: [{
+ id: 'some-random-id-value',
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID'
+ }
+ }]
+ },
+ {
+ source: 'id5-sync.com',
+ uids: [{
+ id: 'some-random-id-value',
+ atype: 1
+ }]
+ },
+ {
+ source: 'sharedid.org',
+ uids: [{
+ id: 'some-random-id-value',
+ atype: 1,
+ ext: {
+ third: 'some-random-id-value'
+ }
+ }]
}
- );
-
- const request = spec.buildRequests([bidRequest], mockBidderRequest);
- const dataParams = request[0].data;
-
- expect(dataParams.aumfs).to.exist;
- expect(dataParams.aumfs).to.equal('1500');
- });
+ ];
- context('with floors module', function () {
- let adServerCurrencyStub;
- function makeBidWithFloorInfo(floorInfo) {
- return Object.assign(utils.deepClone(bidRequestsWithMediaTypes[0]),
- {
- getFloor: () => {
- return floorInfo;
+ it(`should send the user id under the extended ids`, function () {
+ const bidRequestsWithUserId = [{
+ bidder: 'openx',
+ params: {
+ unit: '11',
+ delDomain: 'test-del-domain'
+ },
+ userId: {
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]]
}
- });
- }
-
- beforeEach(function () {
- adServerCurrencyStub = sinon
- .stub(config, 'getConfig')
- .withArgs('currency.adServerCurrency')
+ },
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ userIdAsEids: userIdAsEids
+ }];
+ // enrich bid request with userId key/value
+
+ const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
+ expect(request[0].data.user.ext.eids).to.equal(userIdAsEids);
});
- afterEach(function () {
- config.getConfig.restore();
+ it(`when no user ids are available, it should not send any extended ids`, function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].data).to.not.have.any.keys('user');
});
+ });
- it('should send out floors on bids', function () {
- const floors = [9.99, 18.881];
- const bidRequests = floors.map(floor => {
- return makeBidWithFloorInfo({
- currency: 'AUS',
- floor: floor
- });
+ context('FLEDGE', function() {
+ it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, {
+ ...mockBidderRequest,
+ fledgeEnabled: true
});
- const request = spec.buildRequests(bidRequests, mockBidderRequest);
-
- expect(request[0].data.aumfs).to.exist;
- expect(request[0].data.aumfs).to.equal('9990');
- expect(request[1].data.aumfs).to.exist;
- expect(request[1].data.aumfs).to.equal('18881');
+ expect(request[0].data.imp[0].ext.ae).to.equal(2);
});
+ });
+ });
- it('should send out floors on bids in the default currency', function () {
- const bidRequest1 = makeBidWithFloorInfo({});
-
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
+ context('banner', function () {
+ it('should send bid request with a mediaTypes specified with banner type', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[0].data.imp[0]).to.have.any.keys(BANNER);
+ });
+ });
- spec.buildRequests([bidRequest1], mockBidderRequest);
- expect(getFloorSpy.args[0][0].mediaType).to.equal(VIDEO);
- expect(getFloorSpy.args[0][0].currency).to.equal('USD');
+ if (FEATURES.VIDEO) {
+ context('video', function () {
+ it('should send bid request with a mediaTypes specified with video type', function () {
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(request[1].data.imp[0]).to.have.any.keys(VIDEO);
});
- it('should send out floors on bids in the ad server currency if defined', function () {
- adServerCurrencyStub.returns('bitcoin');
-
- const bidRequest1 = makeBidWithFloorInfo({});
-
- let getFloorSpy = sinon.spy(bidRequest1, 'getFloor');
-
- spec.buildRequests([bidRequest1], mockBidderRequest);
- expect(getFloorSpy.args[0][0].mediaType).to.equal(VIDEO);
- expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin');
+ it('Update imp.video with OpenRTB options from mimeTypes and params', function() {
+ const bid01 = new BidRequestBuilder({
+ adUnitCode: 'adunit-code-01',
+ mediaTypes: {
+ banner: { sizes: [[300, 250]] },
+ video: {
+ context: 'outstream',
+ playerSize: [[300, 250]],
+ mimes: ['video/mp4'],
+ protocols: [8]
+ }
+ },
+ }).withParams({
+ // options in video, will merge
+ video: {
+ skip: 1,
+ skipafter: 4,
+ minduration: 10,
+ maxduration: 30
+ }
+ }).build();
+
+ const bidderRequest = new BidderRequestBuilder().build();
+ const expected = {
+ mimes: ['video/mp4'],
+ skip: 1,
+ skipafter: 4,
+ minduration: 10,
+ maxduration: 30,
+ placement: 4,
+ protocols: [8],
+ w: 300,
+ h: 250
+ };
+ const requests = spec.buildRequests([bid01], bidderRequest);
+ expect(requests).to.have.lengthOf(2);
+ expect(requests[1].data.imp[0].video).to.deep.equal(expected);
});
- })
- })
+ });
+ }
});
- describe('buildRequest for multi-format ad', function () {
- const multiformatBid = MULTI_FORMAT_BID_REQUESTS[0];
- let mockBidderRequest = {refererInfo: {}};
+ describe('interpretResponse()', function () {
+ let bidRequestConfigs;
+ let bidRequest;
+ let bidResponse;
+ let bid;
- it('should default to a banner request', function () {
- const request = spec.buildRequests([multiformatBid], mockBidderRequest);
- const dataParams = request[0].data;
-
- expect(dataParams.divids).to.have.string(multiformatBid.adUnitCode);
- });
- });
-
- describe('buildRequests for all kinds of ads', function () {
- utils._each({
- banner: BANNER_BID_REQUESTS_WITH_MEDIA_TYPES[0],
- video: VIDEO_BID_REQUESTS_WITH_MEDIA_TYPES[0],
- multi: MULTI_FORMAT_BID_REQUESTS[0]
- }, (bidRequest, name) => {
- describe('with segments', function () {
- const TESTS = [
- {
- name: 'should send proprietary segment data from ortb2.user.data',
- config: {
- ortb2: {
- user: {
- data: [
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp2', segment: [{id: 'baz'}]},
- ]
- }
- }
- },
- expect: {sm: 'dmp1/4:foo|bar,dmp2:baz'},
- },
- {
- name: 'should send proprietary segment data from ortb2.site.content.data',
- config: {
- ortb2: {
- site: {
- content: {
- data: [
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp2', segment: [{id: 'baz'}]},
- ]
- }
- }
- }
- },
- expect: {scsm: 'dmp1/4:foo|bar,dmp2:baz'},
- },
- {
- name: 'should send proprietary segment data from both ortb2.site.content.data and ortb2.user.data',
- config: {
- ortb2: {
- user: {
- data: [
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp2', segment: [{id: 'baz'}]},
- ]
- },
- site: {
- content: {
- data: [
- {name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
- {name: 'dmp4', segment: [{id: 'baz2'}]},
- ]
- }
- }
- }
- },
- expect: {
- sm: 'dmp1/4:foo|bar,dmp2:baz',
- scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
- },
- },
- {
- name: 'should combine same provider segment data from ortb2.user.data',
- config: {
- ortb2: {
- user: {
- data: [
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp1', ext: {}, segment: [{id: 'baz'}]},
- ]
- }
- }
- },
- expect: {sm: 'dmp1/4:foo|bar,dmp1:baz'},
- },
- {
- name: 'should combine same provider segment data from ortb2.site.content.data',
- config: {
- ortb2: {
- site: {
- content: {
- data: [
- {name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp1', ext: {}, segment: [{id: 'baz'}]},
- ]
- }
- }
- }
- },
- expect: {scsm: 'dmp1/4:foo|bar,dmp1:baz'},
- },
- {
- name: 'should not send any segment data if first party config is incomplete',
- config: {
- ortb2: {
- user: {
- data: [
- {name: 'provider-with-no-segments'},
- {segment: [{id: 'segments-with-no-provider'}]},
- {},
- ]
- }
- }
- }
+ context('when there is an nbr response', function () {
+ let bids;
+ beforeEach(function () {
+ bidRequestConfigs = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
},
- {
- name: 'should send first party data segments and liveintent segments from request',
- config: {
- ortb2: {
- user: {
- data: [
- {name: 'dmp1', segment: [{id: 'foo'}, {id: 'bar'}]},
- {name: 'dmp2', segment: [{id: 'baz'}]},
- ]
- },
- site: {
- content: {
- data: [
- {name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
- {name: 'dmp4', segment: [{id: 'baz2'}]},
- ]
- }
- }
- }
- },
- request: {
- userId: {
- lipb: {
- lipbid: 'aaa',
- segments: ['l1', 'l2']
- },
- },
- },
- expect: {
- sm: 'dmp1:foo|bar,dmp2:baz,liveintent:l1|l2',
- scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
},
},
- {
- name: 'should send just liveintent segment from request if no first party config',
- config: {},
- request: {
- userId: {
- lipb: {
- lipbid: 'aaa',
- segments: ['l1', 'l2']
- },
- },
- },
- expect: {sm: 'liveintent:l1|l2'},
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
+
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+
+ bidResponse = {nbr: 0}; // Unknown error
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
+ });
+
+ it('should not return any bids', function () {
+ expect(bids.length).to.equal(0);
+ });
+ });
+
+ context('when no seatbid in response', function () {
+ let bids;
+ beforeEach(function () {
+ bidRequestConfigs = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
},
- {
- name: 'should send nothing if lipb section does not contain segments',
- config: {},
- request: {
- userId: {
- lipb: {
- lipbid: 'aaa',
- },
- },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
},
},
- ];
- utils._each(TESTS, (t) => {
- context('in ortb2.user.data', function () {
- let bidRequests;
- beforeEach(function () {
- bidRequests = [{...bidRequest, ...t.request}];
- });
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
- const mockBidderRequest = {refererInfo: {}, ortb2: t.config.ortb2};
- it(`${t.name} for type ${name}`, function () {
- const request = spec.buildRequests(bidRequests, mockBidderRequest)
- expect(request.length).to.equal(1);
- if (t.expect) {
- for (const key in t.expect) {
- expect(request[0].data[key]).to.exist;
- expect(request[0].data[key]).to.equal(t.expect[key]);
- }
- } else {
- expect(request[0].data.sm).to.not.exist;
- expect(request[0].data.scsm).to.not.exist;
- }
- });
- });
- });
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+
+ bidResponse = {ext: {}, id: 'test-bid-id'};
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
});
- describe('with user agent client hints', function () {
- it('should add json query param sua with BidRequest.device.sua if available', function () {
- const bidderRequestWithUserAgentClientHints = { refererInfo: {},
- ortb2: {
- device: {
- sua: {
- source: 2,
- platform: {
- brand: 'macOS',
- version: [ '12', '4', '0' ]
- },
- browsers: [
- {
- brand: 'Chromium',
- version: [ '106', '0', '5249', '119' ]
- },
- {
- brand: 'Google Chrome',
- version: [ '106', '0', '5249', '119' ]
- },
- {
- brand: 'Not;A=Brand',
- version: [ '99', '0', '0', '0' ]
- }],
- mobile: 0,
- model: 'Pro',
- bitness: '64',
- architecture: 'x86'
- }
- }
- }};
-
- let request = spec.buildRequests([bidRequest], bidderRequestWithUserAgentClientHints);
- expect(request[0].data.sua).to.exist;
- const payload = JSON.parse(request[0].data.sua);
- expect(payload).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua);
- const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}};
- request = spec.buildRequests([bidRequest], bidderRequestWithoutUserAgentClientHints);
- expect(request[0].data.sua).to.not.exist;
- });
+
+ it('should not return any bids', function () {
+ expect(bids.length).to.equal(0);
});
});
- })
- describe('interpretResponse for banner ads', function () {
- beforeEach(function () {
- sinon.spy(userSync, 'registerSync');
- });
+ context('when there is no response', function () {
+ let bids;
+ beforeEach(function () {
+ bidRequestConfigs = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ },
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
+
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
- afterEach(function () {
- userSync.registerSync.restore();
+ bidResponse = ''; // Unknown error
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
+ });
+
+ it('should not return any bids', function () {
+ expect(bids.length).to.equal(0);
+ });
});
- describe('when there is a standard response', function () {
- const creativeOverride = {
- id: 234,
- width: '300',
- height: '250',
- tracking: {
- impression: 'https://openx-d.openx.net/v/1.0/ri?ts=ts'
+ const SAMPLE_BID_REQUESTS = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ },
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
+
+ const SAMPLE_BID_RESPONSE = {
+ seatbid: [{
+ bid: [{
+ impid: 'test-bid-id',
+ price: 2,
+ w: 300,
+ h: 250,
+ crid: 'test-creative-id',
+ dealid: 'test-deal-id',
+ adm: 'test-ad-markup',
+ adomain: ['brand.com'],
+ ext: {
+ dsp_id: '123',
+ buyer_id: '456',
+ brand_id: '789',
+ paf: {
+ content_id: 'paf_content_id'
+ }
+ }
+ }]
+ }],
+ cur: 'AUS',
+ ext: {
+ paf: {
+ transmission: {version: '12'}
}
- };
-
- const adUnitOverride = {
- ts: 'test-1234567890-ts',
- idx: '0',
- currency: 'USD',
- pub_rev: '10000',
- html: 'OpenX Ad
'
- };
- let adUnit;
- let bidResponse;
-
- let bid;
- let bidRequest;
- let bidRequestConfigs;
+ }
+ };
+ context('when there is a response, the common response properties', function () {
beforeEach(function () {
- bidRequestConfigs = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- 'mediaType': 'banner',
- 'sizes': [[300, 250], [300, 600]],
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475'
- }];
-
- bidRequest = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/arj',
- data: {},
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
- };
+ bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS);
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+ bidResponse = deepClone(SAMPLE_BID_RESPONSE);
- adUnit = mockAdUnit(adUnitOverride, creativeOverride);
- bidResponse = mockArjResponse(undefined, [adUnit]);
bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
});
it('should return a price', function () {
- expect(bid.cpm).to.equal(parseInt(adUnitOverride.pub_rev, 10) / 1000);
+ expect(bid.cpm).to.equal(bidResponse.seatbid[0].bid[0].price);
});
it('should return a request id', function () {
- expect(bid.requestId).to.equal(bidRequest.payload.bids[0].bidId);
+ expect(bid.requestId).to.equal(bidResponse.seatbid[0].bid[0].impid);
});
it('should return width and height for the creative', function () {
- expect(bid.width).to.equal(creativeOverride.width);
- expect(bid.height).to.equal(creativeOverride.height);
+ expect(bid.width).to.equal(bidResponse.seatbid[0].bid[0].w);
+ expect(bid.height).to.equal(bidResponse.seatbid[0].bid[0].h);
});
it('should return a creativeId', function () {
- expect(bid.creativeId).to.equal(creativeOverride.id);
+ expect(bid.creativeId).to.equal(bidResponse.seatbid[0].bid[0].crid);
});
it('should return an ad', function () {
- expect(bid.ad).to.equal(adUnitOverride.html);
+ expect(bid.ad).to.equal(bidResponse.seatbid[0].bid[0].adm);
+ });
+
+ it('should return a deal id if it exists', function () {
+ expect(bid.dealId).to.equal(bidResponse.seatbid[0].bid[0].dealid);
});
it('should have a time-to-live of 5 minutes', function () {
@@ -1863,415 +1286,293 @@ describe('OpenxAdapter', function () {
});
it('should return a currency', function () {
- expect(bid.currency).to.equal(adUnitOverride.currency);
- });
-
- it('should return a transaction state', function () {
- expect(bid.ts).to.equal(adUnitOverride.ts);
+ expect(bid.currency).to.equal(bidResponse.cur);
});
it('should return a brand ID', function () {
- expect(bid.meta.brandId).to.equal(DEFAULT_TEST_ARJ_AD_UNIT.brand_id);
+ expect(bid.meta.brandId).to.equal(bidResponse.seatbid[0].bid[0].ext.brand_id);
});
- it('should return an adomain', function () {
- expect(bid.meta.advertiserDomains).to.deep.equal([]);
+ it('should return a dsp ID', function () {
+ expect(bid.meta.networkId).to.equal(bidResponse.seatbid[0].bid[0].ext.dsp_id);
});
- it('should return a dsp ID', function () {
- expect(bid.meta.dspid).to.equal(DEFAULT_TEST_ARJ_AD_UNIT.adv_id);
+ it('should return a buyer ID', function () {
+ expect(bid.meta.advertiserId).to.equal(bidResponse.seatbid[0].bid[0].ext.buyer_id);
});
- });
- describe('when there is a deal', function () {
- const adUnitOverride = {
- deal_id: 'ox-1000'
- };
- let adUnit;
- let bidResponse;
+ it('should return adomain', function () {
+ expect(bid.meta.advertiserDomains).to.equal(bidResponse.seatbid[0].bid[0].adomain);
+ });
- let bid;
- let bidRequestConfigs;
- let bidRequest;
+ it('should return paf fields', function () {
+ const paf = {
+ transmission: {version: '12'},
+ content_id: 'paf_content_id'
+ }
+ expect(bid.meta.paf).to.deep.equal(paf);
+ });
+ });
+ context('when there is more than one response', () => {
+ let bids;
beforeEach(function () {
- bidRequestConfigs = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- 'mediaType': 'banner',
- 'sizes': [[300, 250], [300, 600]],
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475'
- }];
+ bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS);
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+ bidResponse = deepClone(SAMPLE_BID_RESPONSE);
+ bidResponse.seatbid[0].bid.push(deepClone(bidResponse.seatbid[0].bid[0]));
+ bidResponse.seatbid[0].bid[1].ext.paf.content_id = 'second_paf'
- bidRequest = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/arj',
- data: {},
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
- };
- adUnit = mockAdUnit(adUnitOverride);
- bidResponse = mockArjResponse(null, [adUnit]);
- bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
- mockArjResponse();
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
});
- it('should return a deal id', function () {
- expect(bid.dealId).to.equal(adUnitOverride.deal_id);
+ it('should not confuse paf content_id', () => {
+ expect(bids.map(b => b.meta.paf.content_id)).to.eql(['paf_content_id', 'second_paf']);
});
- });
-
- describe('when there is no bids in the response', function () {
- let bidRequest;
- let bidRequestConfigs;
+ })
+ context('when the response is a banner', function() {
beforeEach(function () {
bidRequestConfigs = [{
- 'bidder': 'openx',
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
},
- 'adUnitCode': 'adunit-code',
- 'mediaType': 'banner',
- 'sizes': [[300, 250], [300, 600]],
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475'
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ },
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
}];
- bidRequest = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/arj',
- data: {},
- payload: {'bids': bidRequestConfigs, 'startTime': new Date()}
- };
- });
-
- it('handles nobid responses', function () {
- const bidResponse = {
- 'ads':
- {
- 'version': 1,
- 'count': 1,
- 'pixels': 'https://testpixels.net',
- 'ad': []
- }
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+
+ bidResponse = {
+ seatbid: [{
+ bid: [{
+ impid: 'test-bid-id',
+ price: 2,
+ w: 300,
+ h: 250,
+ crid: 'test-creative-id',
+ dealid: 'test-deal-id',
+ adm: 'test-ad-markup'
+ }]
+ }],
+ cur: 'AUS'
};
- const result = spec.interpretResponse({body: bidResponse}, bidRequest);
- expect(result.length).to.equal(0);
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
});
- });
- describe('when adunits return out of order', function () {
- const bidRequests = [{
- bidder: 'openx',
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[100, 111]]
- }
- },
- bidId: 'test-bid-request-id-1',
- bidderRequestId: 'test-request-1',
- auctionId: 'test-auction-id-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[200, 222]]
- }
- },
- bidId: 'test-bid-request-id-2',
- bidderRequestId: 'test-request-1',
- auctionId: 'test-auction-id-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '12345678',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 333]]
- }
- },
- 'bidId': 'test-bid-request-id-3',
- 'bidderRequestId': 'test-request-1',
- 'auctionId': 'test-auction-id-1'
- }];
- const bidRequest = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/arj',
- data: {},
- payload: {'bids': bidRequests, 'startTime': new Date()}
- };
-
- let outOfOrderAdunits = [
- mockAdUnit({
- idx: '1'
- }, {
- width: bidRequests[1].mediaTypes.banner.sizes[0][0],
- height: bidRequests[1].mediaTypes.banner.sizes[0][1]
- }),
- mockAdUnit({
- idx: '2'
- }, {
- width: bidRequests[2].mediaTypes.banner.sizes[0][0],
- height: bidRequests[2].mediaTypes.banner.sizes[0][1]
- }),
- mockAdUnit({
- idx: '0'
- }, {
- width: bidRequests[0].mediaTypes.banner.sizes[0][0],
- height: bidRequests[0].mediaTypes.banner.sizes[0][1]
- })
- ];
-
- let bidResponse = mockArjResponse(undefined, outOfOrderAdunits);
-
- it('should return map adunits back to the proper request', function () {
- const bids = spec.interpretResponse({body: bidResponse}, bidRequest);
- expect(bids[0].requestId).to.equal(bidRequests[1].bidId);
- expect(bids[0].width).to.equal(bidRequests[1].mediaTypes.banner.sizes[0][0]);
- expect(bids[0].height).to.equal(bidRequests[1].mediaTypes.banner.sizes[0][1]);
- expect(bids[1].requestId).to.equal(bidRequests[2].bidId);
- expect(bids[1].width).to.equal(bidRequests[2].mediaTypes.banner.sizes[0][0]);
- expect(bids[1].height).to.equal(bidRequests[2].mediaTypes.banner.sizes[0][1]);
- expect(bids[2].requestId).to.equal(bidRequests[0].bidId);
- expect(bids[2].width).to.equal(bidRequests[0].mediaTypes.banner.sizes[0][0]);
- expect(bids[2].height).to.equal(bidRequests[0].mediaTypes.banner.sizes[0][1]);
+ it('should return the proper mediaType', function () {
+ it('should return a creativeId', function () {
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
+ });
});
});
- });
-
- describe('interpretResponse for video ads', function () {
- beforeEach(function () {
- sinon.spy(userSync, 'registerSync');
- });
- afterEach(function () {
- userSync.registerSync.restore();
- });
-
- const bidsWithMediaTypes = [{
- 'bidder': 'openx',
- 'mediaTypes': {video: {}},
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- 'sizes': [640, 480],
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475',
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
- }];
- const bidsWithMediaType = [{
- 'bidder': 'openx',
- 'mediaType': 'video',
- 'params': {
- 'unit': '12345678',
- 'delDomain': 'test-del-domain'
- },
- 'adUnitCode': 'adunit-code',
- 'sizes': [640, 480],
- 'bidId': '30b31c1838de1e',
- 'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475',
- 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
- }];
- const bidRequestsWithMediaTypes = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/avjp',
- data: {},
- payload: {'bid': bidsWithMediaTypes[0], 'startTime': new Date()}
- };
- const bidRequestsWithMediaType = {
- method: 'GET',
- url: 'https://openx-d.openx.net/v/1.0/avjp',
- data: {},
- payload: {'bid': bidsWithMediaType[0], 'startTime': new Date()}
- };
- const bidResponse = {
- 'pub_rev': '1000',
- 'width': '640',
- 'height': '480',
- 'adid': '5678',
- 'currency': 'AUD',
- 'vastUrl': 'https://testvast.com',
- 'pixels': 'https://testpixels.net'
- };
+ if (FEATURES.VIDEO) {
+ context('when the response is a video', function() {
+ beforeEach(function () {
+ bidRequestConfigs = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ video: {
+ playerSize: [[640, 360], [854, 480]],
+ },
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
+
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+
+ bidResponse = {
+ seatbid: [{
+ bid: [{
+ impid: 'test-bid-id',
+ price: 2,
+ w: 854,
+ h: 480,
+ crid: 'test-creative-id',
+ dealid: 'test-deal-id',
+ adm: 'test-ad-markup',
+ }]
+ }],
+ cur: 'AUS'
+ };
+ });
- it('should return correct bid response with MediaTypes', function () {
- const expectedResponse = {
- 'requestId': '30b31c1838de1e',
- 'cpm': 1,
- 'width': 640,
- 'height': 480,
- 'mediaType': 'video',
- 'creativeId': '5678',
- 'vastUrl': 'https://testvast.com',
- 'ttl': 300,
- 'netRevenue': true,
- 'currency': 'AUD'
- };
-
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes);
- expect(result[0]).to.eql(expectedResponse);
- });
+ it('should return the proper mediaType', function () {
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
+ });
- it('should return correct bid response with MediaType', function () {
- const expectedResponse = [
- {
- 'requestId': '30b31c1838de1e',
- 'cpm': 1,
- 'width': '640',
- 'height': '480',
- 'mediaType': 'video',
- 'creativeId': '5678',
- 'vastUrl': 'https://testvast.com',
- 'ttl': 300,
- 'netRevenue': true,
- 'currency': 'USD'
- }
- ];
+ it('should return the proper mediaType', function () {
+ const winUrl = 'https//my.win.url';
+ bidResponse.seatbid[0].bid[0].nurl = winUrl
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaType);
- expect(JSON.stringify(Object.keys(result[0]).sort())).to.eql(JSON.stringify(Object.keys(expectedResponse[0]).sort()));
- });
+ expect(bid.vastUrl).to.equal(winUrl);
+ });
+ });
+ }
- it('should return correct bid response with MediaType and deal_id', function () {
- const bidResponseOverride = { 'deal_id': 'OX-mydeal' };
- const bidResponseWithDealId = Object.assign({}, bidResponse, bidResponseOverride);
- const result = spec.interpretResponse({body: bidResponseWithDealId}, bidRequestsWithMediaType);
- expect(result[0].dealId).to.equal(bidResponseOverride.deal_id);
- });
+ context('when the response contains FLEDGE interest groups config', function() {
+ let response;
- it('should handle nobid responses for bidRequests with MediaTypes', function () {
- const bidResponse = {'vastUrl': '', 'pub_rev': '', 'width': '', 'height': '', 'adid': '', 'pixels': ''};
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes);
- expect(result.length).to.equal(0);
- });
+ beforeEach(function () {
+ sinon.stub(config, 'getConfig')
+ .withArgs('fledgeEnabled')
+ .returns(true);
- it('should handle nobid responses for bidRequests with MediaType', function () {
- const bidResponse = {'vastUrl': '', 'pub_rev': '', 'width': '', 'height': '', 'adid': '', 'pixels': ''};
- const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaType);
- expect(result.length).to.equal(0);
- });
- });
+ bidRequestConfigs = [{
+ bidder: 'openx',
+ params: {
+ unit: '12345678',
+ delDomain: 'test-del-domain'
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ },
+ },
+ bidId: 'test-bid-id',
+ bidderRequestId: 'test-bidder-request-id',
+ auctionId: 'test-auction-id'
+ }];
- describe('user sync', function () {
- const syncUrl = 'https://testpixels.net';
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
+
+ bidResponse = {
+ seatbid: [{
+ bid: [{
+ impid: 'test-bid-id',
+ price: 2,
+ w: 300,
+ h: 250,
+ crid: 'test-creative-id',
+ dealid: 'test-deal-id',
+ adm: 'test-ad-markup'
+ }]
+ }],
+ cur: 'AUS',
+ ext: {
+ fledge_auction_configs: {
+ 'test-bid-id': {
+ seller: 'codinginadtech.com',
+ interestGroupBuyers: ['somedomain.com'],
+ sellerTimeout: 0,
+ perBuyerSignals: {
+ 'somedomain.com': {
+ base_bid_micros: 0.1,
+ disallowed_advertiser_ids: [
+ '1234',
+ '2345'
+ ],
+ multiplier: 1.3,
+ use_bid_multiplier: true,
+ win_reporting_id: '1234567asdf'
+ }
+ }
+ }
+ }
+ }
+ };
- describe('iframe sync', function () {
- it('should register the pixel iframe from banner ad response', function () {
- let syncs = spec.getUserSyncs(
- {iframeEnabled: true},
- [{body: {ads: {pixels: syncUrl}}}]
- );
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
+ response = spec.interpretResponse({body: bidResponse}, bidRequest);
});
- it('should register the pixel iframe from video ad response', function () {
- let syncs = spec.getUserSyncs(
- {iframeEnabled: true},
- [{body: {pixels: syncUrl}}]
- );
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
+ afterEach(function () {
+ config.getConfig.restore();
});
- it('should register the default iframe if no pixels available', function () {
- let syncs = spec.getUserSyncs(
- {iframeEnabled: true},
- []
- );
- expect(syncs).to.deep.equal([{type: 'iframe', url: 'https://u.openx.net/w/1.0/pd'}]);
+ it('should return FLEDGE auction_configs alongside bids', function () {
+ expect(response).to.have.property('bids');
+ expect(response).to.have.property('fledgeAuctionConfigs');
+ expect(response.fledgeAuctionConfigs.length).to.equal(1);
+ expect(response.fledgeAuctionConfigs[0].bidId).to.equal('test-bid-id');
});
});
+ });
- describe('pixel sync', function () {
- it('should register the image pixel from banner ad response', function () {
- let syncs = spec.getUserSyncs(
- {pixelEnabled: true},
- [{body: {ads: {pixels: syncUrl}}}]
- );
- expect(syncs).to.deep.equal([{type: 'image', url: syncUrl}]);
- });
+ describe('user sync', function () {
+ it('should register the default image pixel if no pixels available', function () {
+ let syncs = spec.getUserSyncs(
+ {pixelEnabled: true},
+ []
+ );
+ expect(syncs).to.deep.equal([{type: 'image', url: DEFAULT_SYNC}]);
+ });
- it('should register the image pixel from video ad response', function () {
- let syncs = spec.getUserSyncs(
- {pixelEnabled: true},
- [{body: {pixels: syncUrl}}]
- );
- expect(syncs).to.deep.equal([{type: 'image', url: syncUrl}]);
- });
+ it('should register custom syncUrl when exists', function () {
+ let syncs = spec.getUserSyncs(
+ {pixelEnabled: true},
+ [{body: {ext: {delDomain: 'www.url.com'}}}]
+ );
+ expect(syncs).to.deep.equal([{type: 'image', url: 'https://www.url.com/w/1.0/pd'}]);
+ });
- it('should register the default image pixel if no pixels available', function () {
- let syncs = spec.getUserSyncs(
- {pixelEnabled: true},
- []
- );
- expect(syncs).to.deep.equal([{type: 'image', url: 'https://u.openx.net/w/1.0/pd'}]);
- });
+ it('should register custom syncUrl when exists', function () {
+ let syncs = spec.getUserSyncs(
+ {pixelEnabled: true},
+ [{body: {ext: {platform: 'abc'}}}]
+ );
+ expect(syncs).to.deep.equal([{type: 'image', url: SYNC_URL + '?ph=abc'}]);
+ });
+
+ it('when iframe sync is allowed, it should register an iframe sync', function () {
+ let syncs = spec.getUserSyncs(
+ {iframeEnabled: true},
+ []
+ );
+ expect(syncs).to.deep.equal([{type: 'iframe', url: DEFAULT_SYNC}]);
});
it('should prioritize iframe over image for user sync', function () {
let syncs = spec.getUserSyncs(
{iframeEnabled: true, pixelEnabled: true},
- [{body: {ads: {pixels: syncUrl}}}]
+ []
);
- expect(syncs).to.deep.equal([{type: 'iframe', url: syncUrl}]);
+ expect(syncs).to.deep.equal([{type: 'iframe', url: DEFAULT_SYNC}]);
});
describe('when gdpr applies', function () {
let gdprConsent;
let gdprPixelUrl;
+ const consentString = 'gdpr-pixel-consent';
+ const gdprApplies = '1';
beforeEach(() => {
gdprConsent = {
- consentString: 'test-gdpr-consent-string',
+ consentString,
gdprApplies: true
};
- gdprPixelUrl = 'https://testpixels.net?gdpr=1&gdpr_consent=gdpr-pixel-consent'
+ gdprPixelUrl = `${SYNC_URL}&gdpr=${gdprApplies}&gdpr_consent=${consentString}`;
});
it('when there is a response, it should have the gdpr query params', () => {
- let [{url}] = spec.getUserSyncs(
- {iframeEnabled: true, pixelEnabled: true},
- [{body: {ads: {pixels: gdprPixelUrl}}}],
- gdprConsent
- );
-
- expect(url).to.have.string('gdpr_consent=gdpr-pixel-consent');
- expect(url).to.have.string('gdpr=1');
- });
-
- it('when there is no response, it should append gdpr query params', () => {
let [{url}] = spec.getUserSyncs(
{iframeEnabled: true, pixelEnabled: true},
[],
gdprConsent
);
- expect(url).to.have.string('gdpr_consent=test-gdpr-consent-string');
- expect(url).to.have.string('gdpr=1');
+
+ expect(url).to.have.string(`gdpr_consent=${consentString}`);
+ expect(url).to.have.string(`gdpr=${gdprApplies}`);
});
it('should not send signals if no consent object is available', function () {
@@ -2287,28 +1588,19 @@ describe('OpenxAdapter', function () {
describe('when ccpa applies', function () {
let usPrivacyConsent;
let uspPixelUrl;
+ const privacyString = 'TEST';
beforeEach(() => {
usPrivacyConsent = 'TEST';
- uspPixelUrl = 'https://testpixels.net?us_privacy=AAAA'
+ uspPixelUrl = `${DEFAULT_SYNC}&us_privacy=${privacyString}`
});
- it('when there is a response, it should send the us privacy string from the response, ', () => {
- let [{url}] = spec.getUserSyncs(
- {iframeEnabled: true, pixelEnabled: true},
- [{body: {ads: {pixels: uspPixelUrl}}}],
- undefined,
- usPrivacyConsent
- );
-
- expect(url).to.have.string('us_privacy=AAAA');
- });
- it('when there is no response, it send have the us privacy string', () => {
+ it('should send the us privacy string, ', () => {
let [{url}] = spec.getUserSyncs(
{iframeEnabled: true, pixelEnabled: true},
[],
undefined,
usPrivacyConsent
);
- expect(url).to.have.string(`us_privacy=${usPrivacyConsent}`);
+ expect(url).to.have.string(`us_privacy=${privacyString}`);
});
it('should not send signals if no consent string is available', function () {
@@ -2320,75 +1612,4 @@ describe('OpenxAdapter', function () {
});
});
});
-
- /**
- * Makes sure the override object does not introduce
- * new fields against the contract
- *
- * This does a shallow check in order to make key checking simple
- * with respect to what a helper handles. For helpers that have
- * nested fields, either check your design on maybe breaking it up
- * to smaller, manageable pieces
- *
- * OR just call this on your nth level field if necessary.
- *
- * @param {Object} override Object with keys that overrides the default
- * @param {Object} contract Original object contains the default fields
- * @param {string} typeName Name of the type we're checking for error messages
- * @throws {AssertionError}
- */
- function overrideKeyCheck(override, contract, typeName) {
- expect(contract).to.include.all.keys(Object.keys(override));
- }
-
- /**
- * Creates a mock ArjResponse
- * @param {OxArjResponse=} response
- * @param {Array=} adUnits
- * @throws {AssertionError}
- * @return {OxArjResponse}
- */
- function mockArjResponse(response, adUnits = []) {
- let mockedArjResponse = utils.deepClone(DEFAULT_ARJ_RESPONSE);
-
- if (response) {
- overrideKeyCheck(response, DEFAULT_ARJ_RESPONSE, 'OxArjResponse');
- overrideKeyCheck(response.ads, DEFAULT_ARJ_RESPONSE.ads, 'OxArjResponse');
- Object.assign(mockedArjResponse, response);
- }
-
- if (adUnits.length) {
- mockedArjResponse.ads.count = adUnits.length;
- mockedArjResponse.ads.ad = adUnits.map((adUnit) => {
- overrideKeyCheck(adUnit, DEFAULT_TEST_ARJ_AD_UNIT, 'OxArjAdUnit');
- return Object.assign(utils.deepClone(DEFAULT_TEST_ARJ_AD_UNIT), adUnit);
- });
- }
-
- return mockedArjResponse;
- }
-
- /**
- * Creates a mock ArjAdUnit
- * @param {OxArjAdUnit=} adUnit
- * @param {OxArjCreative=} creative
- * @throws {AssertionError}
- * @return {OxArjAdUnit}
- */
- function mockAdUnit(adUnit, creative) {
- overrideKeyCheck(adUnit, DEFAULT_TEST_ARJ_AD_UNIT, 'OxArjAdUnit');
-
- let mockedAdUnit = Object.assign(utils.deepClone(DEFAULT_TEST_ARJ_AD_UNIT), adUnit);
-
- if (creative) {
- overrideKeyCheck(creative, DEFAULT_TEST_ARJ_CREATIVE);
- if (creative.tracking) {
- overrideKeyCheck(creative.tracking, DEFAULT_TEST_ARJ_CREATIVE.tracking, 'OxArjCreative');
- }
- Object.assign(mockedAdUnit.creative[0], creative);
- }
-
- return mockedAdUnit;
- }
-})
-;
+});
diff --git a/test/spec/modules/openxOrtbBidAdapter_spec.js b/test/spec/modules/openxOrtbBidAdapter_spec.js
index 951399457c3..d8ea79ac698 100644
--- a/test/spec/modules/openxOrtbBidAdapter_spec.js
+++ b/test/spec/modules/openxOrtbBidAdapter_spec.js
@@ -1096,45 +1096,6 @@ describe('OpenxRtbAdapter', function () {
});
});
}
-
- it.skip('should send ad unit ids when any are defined', function () {
- const bidRequestsWithUnitIds = [{
- bidder: 'openx',
- params: {
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- bidId: 'test-bid-id-1',
- bidderRequestId: 'test-bid-request-1',
- auctionId: 'test-auction-1',
- transactionId: 'test-transaction-id-1'
- }, {
- bidder: 'openx',
- params: {
- unit: '22',
- delDomain: 'test-del-domain'
- },
- adUnitCode: 'adunit-code',
- mediaTypes: {
- banner: {
- sizes: [[728, 90]]
- }
- },
- bidId: 'test-bid-id-2',
- bidderRequestId: 'test-bid-request-2',
- auctionId: 'test-auction-2',
- transactionId: 'test-transaction-id-2'
- }];
- mockBidderRequest.bids = bidRequestsWithUnitIds;
- const request = spec.buildRequests(bidRequestsWithUnitIds, mockBidderRequest);
- expect(request[0].data.imp[1].tagid).to.equal(bidRequestsWithUnitIds[1].params.unit);
- expect(request[0].data.imp[1].ext.divid).to.equal(bidRequestsWithUnitIds[1].params.adUnitCode);
- });
});
describe('interpretResponse()', function () {