diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js
index 18016eea530..c696dabc64a 100644
--- a/modules/improvedigitalBidAdapter.js
+++ b/modules/improvedigitalBidAdapter.js
@@ -1,69 +1,58 @@
import {
- _each,
- deepAccess,
- deepSetValue,
- getBidIdParameter,
- getBidRequest,
- getUniqueIdentifierStr,
- isArray,
- isEmpty,
- isFn,
- isInteger,
- isNumber,
- isPlainObject,
- isStr,
- logError,
- logWarn, mergeDeep
+ cleanObj, deepAccess, deepClone, deepSetValue, getBidIdParameter, getBidRequest, getDNT,
+ getUniqueIdentifierStr, isFn, isPlainObject, logWarn, mergeDeep, parseUrl
} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {config} from '../src/config.js';
import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
import {Renderer} from '../src/Renderer.js';
import {createEidsArray} from './userId/eids.js';
-import {includes} from '../src/polyfill.js';
const BIDDER_CODE = 'improvedigital';
-const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
-const VIDEO_TARGETING = ['skip', 'skipmin', 'skipafter'];
+const REQUEST_URL = 'https://ad.360yield.com/pb';
+const CREATIVE_TTL = 300;
+
+const VIDEO_PARAMS = {
+ DEFAULT_MIMES: ['video/mp4'],
+ SUPPORTED_PROPERTIES: ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
+ 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad',
+ 'api', 'companiontype', 'ext'],
+ PLACEMENT_TYPE: {
+ INSTREAM: 1,
+ OUTSTREAM: 3,
+ }
+};
-const ID_RAZR = {
- RENDERER_URL: 'https://razr.improvedigital.com/renderer.js',
- addBidData({bid, bidRequest}) {
- if (this.isValidBid(bid)) {
- bid.renderer = Renderer.install({
- url: this.RENDERER_URL,
- config: {bidRequest}
- });
- bid.renderer.setRender(this.render);
- }
+const NATIVE_DATA = {
+ VERSION: '1.2',
+ ASSET_TYPES: {
+ TITLE: 'title',
+ IMG: 'img',
+ DATA: 'data',
},
-
- isValidBid(bid) {
- return bid && /razr:\\?\/\\?\//.test(bid.ad);
+ ASSETS: {
+ title: {id: 0, name: 'title', assetType: 'title', default: {len: 140}},
+ sponsoredBy: {id: 1, name: 'sponsoredBy', assetType: 'data', type: 1},
+ icon: {id: 2, name: 'icon', assetType: 'img', type: 2},
+ body: {id: 3, name: 'body', assetType: 'data', type: 2},
+ image: {id: 4, name: 'image', assetType: 'img', type: 3},
+ rating: {id: 5, name: 'rating', assetType: 'data', type: 3},
+ likes: {id: 6, name: 'likes', assetType: 'data', type: 4},
+ downloads: {id: 7, name: 'downloads', assetType: 'data', type: 5},
+ price: {id: 8, name: 'price', assetType: 'data', type: 6},
+ salePrice: {id: 9, name: 'salePrice', assetType: 'data', type: 7},
+ phone: {id: 10, name: 'phone', assetType: 'data', type: 8},
+ address: {id: 11, name: 'address', assetType: 'data', type: 9},
+ body2: {id: 12, name: 'body2', assetType: 'data', type: 10},
+ displayUrl: {id: 13, name: 'displayUrl', assetType: 'data', type: 11},
+ cta: {id: 14, name: 'cta', assetType: 'data', type: 12},
},
-
- render(bid) {
- const {bidRequest} = bid.renderer.getConfig();
-
- const payload = {
- type: 'prebid',
- bidRequest,
- bid,
- config: mergeDeep(
- {},
- config.getConfig('improvedigital.rendererConfig'),
- deepAccess(bidRequest, 'params.rendererConfig')
- )
- };
-
- const razr = window.razr = window.razr || {};
- razr.queue = razr.queue || [];
- razr.queue.push(payload);
+ getAssetById(id) {
+ return Object.values(this.ASSETS).find(asset => id === asset.id);
}
};
export const spec = {
- version: '7.7.0',
code: BIDDER_CODE,
gvlid: 253,
aliases: ['id'],
@@ -75,7 +64,7 @@ export const spec = {
* @param {object} bid The bid to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
- isBidRequestValid: function (bid) {
+ isBidRequestValid(bid) {
return !!(bid && bid.params && (bid.params.placementId || (bid.params.placementKey && bid.params.publisherId)));
},
@@ -83,179 +72,130 @@ export const spec = {
* Make a server request from the list of BidRequests.
*
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server.
+ * @param bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
- buildRequests: function (bidRequests, bidderRequest) {
- let normalizedBids = bidRequests.map((bidRequest) => {
- return getNormalizedBidRequest(bidRequest);
- });
-
- let idClient = new ImproveDigitalAdServerJSClient('hb');
- let requestParameters = {
- singleRequestMode: (config.getConfig('improvedigital.singleRequest') === true),
- returnObjType: idClient.CONSTANTS.RETURN_OBJ_TYPE.URL_PARAMS_SPLIT,
- libVersion: this.version
- };
-
- const gdprConsent = deepAccess(bidderRequest, 'gdprConsent')
- if (gdprConsent) {
- // GDPR Consent String
- if (gdprConsent.consentString) {
- requestParameters.gdpr = gdprConsent.consentString;
- }
-
- // Additional Consent String
- const additionalConsent = deepAccess(gdprConsent, 'addtlConsent');
- if (additionalConsent && additionalConsent.indexOf('~') !== -1) {
- // Google Ad Tech Provider IDs
- const atpIds = additionalConsent.substring(additionalConsent.indexOf('~') + 1);
- deepSetValue(
- requestParameters,
- 'user.ext.consented_providers_settings.consented_providers',
- atpIds.split('.').map(id => parseInt(id, 10))
- );
+ buildRequests(bidRequests, bidderRequest) {
+ const request = {
+ id: getUniqueIdentifierStr(),
+ cur: [config.getConfig('currency.adServerCurrency') || 'USD'],
+ ext: {
+ improvedigital: {
+ sdk: {
+ name: 'pbjs',
+ version: '$prebid.version$',
+ }
+ }
}
- }
+ };
- if (bidderRequest && bidderRequest.uspConsent) {
- requestParameters.usPrivacy = bidderRequest.uspConsent;
+ // Device
+ request.device = (typeof config.getConfig('device') === 'object') ? config.getConfig('device') : {};
+ request.device.w = request.device.w || window.innerWidth;
+ request.device.h = request.device.h || window.innerHeight;
+ if (getDNT()) {
+ request.device.dnt = 1;
}
- if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) {
- requestParameters.referrer = bidderRequest.refererInfo.referer;
+ // Coppa
+ const coppa = config.getConfig('coppa');
+ if (typeof coppa === 'boolean') {
+ deepSetValue(request, 'regs.coppa', ID_UTIL.toBit(coppa));
}
- // Adding first party data
- const site = config.getConfig('ortb2.site');
- if (site) {
- const pageCategory = site.pagecat || site.cat;
- if (pageCategory && isArray(pageCategory)) {
- requestParameters.pagecat = pageCategory.filter((category) => {
- return category && isStr(category)
- });
+ if (bidderRequest) {
+ // GDPR
+ const gdprConsent = deepAccess(bidderRequest, 'gdprConsent')
+ if (gdprConsent) {
+ if (typeof gdprConsent.gdprApplies === 'boolean') {
+ deepSetValue(request, 'regs.ext.gdpr', ID_UTIL.toBit(gdprConsent.gdprApplies));
+ }
+ deepSetValue(request, 'user.ext.consent', gdprConsent.consentString);
+
+ // Additional Consent String
+ const additionalConsent = deepAccess(gdprConsent, 'addtlConsent');
+ if (additionalConsent && additionalConsent.indexOf('~') !== -1) {
+ // Google Ad Tech Provider IDs
+ const atpIds = additionalConsent.substring(additionalConsent.indexOf('~') + 1);
+ deepSetValue(
+ request,
+ 'user.ext.consented_providers_settings.consented_providers',
+ atpIds.split('.').map(id => parseInt(id, 10))
+ );
+ }
}
- const genre = deepAccess(site, 'content.genre');
- if (genre && isStr(genre)) {
- requestParameters.genre = genre;
+
+ // Timeout
+ deepSetValue(request, 'tmax', bidderRequest.timeout);
+ // US Privacy
+ if (typeof bidderRequest.uspConsent !== typeof undefined) {
+ deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}
}
- // End of adding first party data
- requestParameters.schain = bidRequests[0].schain;
- requestParameters.coppa = config.getConfig('coppa') === true;
+ ID_REQUEST.buildSiteOrApp(request, bidderRequest);
- if (bidRequests[0].userId) {
- const eids = createEidsArray(bidRequests[0].userId);
- if (eids.length) {
- deepSetValue(requestParameters, 'user.ext.eids', eids);
- }
- }
+ const bidRequest0 = bidRequests[0];
- let requestObj = idClient.createRequest(
- normalizedBids, // requestObject
- requestParameters
- );
+ deepSetValue(request, 'source.ext.schain', bidRequest0.schain);
+ deepSetValue(request, 'source.tid', bidRequest0.transactionId);
- if (requestObj.errors && requestObj.errors.length > 0) {
- logError('ID WARNING 0x01');
+ if (bidRequest0.userId) {
+ const eids = createEidsArray(bidRequest0.userId);
+ deepSetValue(request, 'user.ext.eids', eids.length ? eids : undefined);
}
- requestObj.requests.forEach(request => request.bidderRequest = bidderRequest);
- return requestObj.requests;
+
+ return ID_REQUEST.buildServerRequests(request, bidRequests, bidderRequest);
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {*} serverResponse A successful response from the server.
+ * @param bidderRequest
* @return {Bid[]} An array of bids which were nested inside the server.
*/
- interpretResponse: function (serverResponse, {bidderRequest}) {
+ interpretResponse(serverResponse, { bidderRequest }) {
+ if (!Array.isArray(deepAccess(serverResponse, 'body.seatbid'))) {
+ return [];
+ }
+
const bids = [];
- _each(serverResponse.body.bid, function (bidObject) {
- if (!bidObject.price || bidObject.price === null ||
- bidObject.hasOwnProperty('errorCode') ||
- (!bidObject.adm && !bidObject.native)) {
- return;
- }
- const bidRequest = getBidRequest(bidObject.id, [bidderRequest]);
- const bid = {};
-
- if (bidObject.native) {
- // Native
- bid.native = getNormalizedNativeAd(bidObject.native);
- // Expose raw oRTB response to the client to allow parsing assets not directly supported by Prebid
- bid.ortbNative = bidObject.native;
- if (bidObject.nurl) {
- bid.native.impressionTrackers.unshift(bidObject.nurl);
- }
- bid.mediaType = NATIVE;
- } else if (bidObject.ad_type && bidObject.ad_type === 'video') {
- bid.vastXml = bidObject.adm;
- bid.mediaType = VIDEO;
- if (isOutstreamVideo(bidRequest)) {
- bid.adResponse = {
- content: bid.vastXml,
- height: bidObject.h,
- width: bidObject.w
- };
- bid.renderer = createRenderer(bidRequest);
- }
- } else {
- // Banner
- let nurl = '';
- if (bidObject.nurl && bidObject.nurl.length > 0) {
- nurl = ``;
- }
- bid.ad = `${nurl}`;
- bid.mediaType = BANNER;
- }
- // Common properties
- bid.cpm = parseFloat(bidObject.price);
- bid.creativeId = bidObject.crid;
- bid.currency = bidObject.currency ? bidObject.currency.toUpperCase() : 'USD';
-
- // Deal ID. Composite ads can have multiple line items and the ID of the first
- // dealID line item will be used.
- if (isNumber(bidObject.lid) && bidObject.buying_type && bidObject.buying_type !== 'rtb') {
- bid.dealId = bidObject.lid;
- } else if (Array.isArray(bidObject.lid) &&
- Array.isArray(bidObject.buying_type) &&
- bidObject.lid.length === bidObject.buying_type.length) {
- let isDeal = false;
- bidObject.buying_type.forEach((bt, i) => {
- if (isDeal) return;
- if (bt && bt !== 'rtb') {
- isDeal = true;
- bid.dealId = bidObject.lid[i];
- }
- });
- }
+ serverResponse.body.seatbid.forEach(seatbid => {
+ if (!Array.isArray(seatbid.bid)) return;
- bid.height = bidObject.h;
- bid.netRevenue = bidObject.isNet ? bidObject.isNet : false;
- bid.requestId = bidObject.id;
- bid.ttl = 300;
- bid.width = bidObject.w;
+ seatbid.bid.forEach(bidObject => {
+ if (!bidObject.adm || !bidObject.price || bidObject.hasOwnProperty('errorCode')) {
+ return;
+ }
+ const bidRequest = getBidRequest(bidObject.impid, [bidderRequest]);
+ const idExt = deepAccess(bidObject, `ext.${BIDDER_CODE}`);
+
+ const bid = {
+ requestId: bidObject.impid,
+ cpm: bidObject.price,
+ creativeId: bidObject.crid,
+ currency: serverResponse.body.cur.toUpperCase() || 'USD',
+ dealId: (typeof idExt.buying_type === 'string' && idExt.buying_type !== 'rtb') ? idExt.line_item_id : undefined,
+ meta: {
+ advertiserDomains: bidObject.adomain ? bidObject.adomain : []
+ },
+ netRevenue: idExt.is_net || false,
+ ttl: CREATIVE_TTL
+ }
- if (!bid.width || !bid.height) {
- bid.width = 1;
- bid.height = 1;
- }
+ ID_RESPONSE.buildAd(bid, bidRequest, bidObject);
- if (bidObject.adomain) {
- bid.meta = {
- advertiserDomains: bidObject.adomain
- };
- }
+ ID_RAZR.addBidData({
+ bidRequest,
+ bid
+ });
- ID_RAZR.addBidData({
- bidRequest,
- bid
+ bids.push(bid);
});
-
- bids.push(bid);
});
+
return bids;
},
@@ -266,17 +206,14 @@ export const spec = {
* @param {ServerResponse[]} serverResponses List of server's responses.
* @return {UserSync[]} The user syncs which should be dropped.
*/
- getUserSyncs: function(syncOptions, serverResponses) {
+ getUserSyncs(syncOptions, serverResponses) {
if (syncOptions.pixelEnabled) {
const syncs = [];
serverResponses.forEach(response => {
- response.body.bid.forEach(bidObject => {
- if (isArray(bidObject.sync)) {
- bidObject.sync.forEach(syncElement => {
- if (syncs.indexOf(syncElement) === -1) {
- syncs.push(syncElement);
- }
- });
+ const syncArr = deepAccess(response, `body.ext.${BIDDER_CODE}.sync`, []);
+ syncArr.forEach(syncElement => {
+ if (syncs.indexOf(syncElement) === -1) {
+ syncs.push(syncElement);
}
});
});
@@ -286,529 +223,374 @@ export const spec = {
}
};
-function isInstreamVideo(bid) {
- const mediaTypes = Object.keys(deepAccess(bid, 'mediaTypes', {}));
- const videoMediaType = deepAccess(bid, 'mediaTypes.video');
- const context = deepAccess(bid, 'mediaTypes.video.context');
- return bid.mediaType === 'video' || (mediaTypes.length === 1 && videoMediaType && context !== 'outstream');
-}
-
-function isOutstreamVideo(bid) {
- const videoMediaType = deepAccess(bid, 'mediaTypes.video');
- const context = deepAccess(bid, 'mediaTypes.video.context');
- return videoMediaType && context === 'outstream';
-}
-
-function getVideoTargetingParams(bid) {
- const result = {};
- Object.keys(Object(bid.mediaTypes.video))
- .filter(key => includes(VIDEO_TARGETING, key))
- .forEach(key => {
- result[ key ] = bid.mediaTypes.video[ key ];
- });
- Object.keys(Object(bid.params.video))
- .filter(key => includes(VIDEO_TARGETING, key))
- .forEach(key => {
- result[ key ] = bid.params.video[ key ];
- });
- return result;
-}
+registerBidder(spec);
-function getBidFloor(bid) {
- if (!isFn(bid.getFloor)) {
- return null;
- }
- const floor = bid.getFloor({
- currency: 'USD',
- mediaType: '*',
- size: '*'
- });
- if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') {
- return floor.floor;
- }
- return null;
-}
-
-function outstreamRender(bid) {
- bid.renderer.push(() => {
- window.ANOutstreamVideo.renderAd({
- sizes: [bid.width, bid.height],
- targetId: bid.adUnitCode,
- adResponse: bid.adResponse,
- rendererOptions: bid.renderer.getConfig()
- }, handleOutstreamRendererEvents.bind(null, bid));
- });
-}
-
-function handleOutstreamRendererEvents(bid, id, eventName) {
- bid.renderer.handleVideoEvent({ id, eventName });
-}
-
-function createRenderer(bidRequest) {
- const renderer = Renderer.install({
- id: bidRequest.adUnitCode,
- url: RENDERER_URL,
- loaded: false,
- config: deepAccess(bidRequest, 'renderer.options'),
- adUnitCode: bidRequest.adUnitCode
- });
- try {
- renderer.setRender(outstreamRender);
- } catch (err) {
- logWarn('Prebid Error calling setRender on renderer', err);
- }
- return renderer;
-}
-
-function getNormalizedBidRequest(bid) {
- let adUnitId = getBidIdParameter('adUnitCode', bid) || null;
- let placementId = getBidIdParameter('placementId', bid.params) || null;
- let publisherId = null;
- let placementKey = null;
-
- if (placementId === null) {
- publisherId = getBidIdParameter('publisherId', bid.params) || null;
- placementKey = getBidIdParameter('placementKey', bid.params) || null;
- }
- const keyValues = getBidIdParameter('keyValues', bid.params) || null;
- const singleSizeFilter = getBidIdParameter('size', bid.params) || null;
- const bidId = getBidIdParameter('bidId', bid);
- const transactionId = getBidIdParameter('transactionId', bid);
- const currency = config.getConfig('currency.adServerCurrency');
-
- let normalizedBidRequest = {};
- if (isInstreamVideo(bid)) {
- normalizedBidRequest.adTypes = [ VIDEO ];
- }
- if (isInstreamVideo(bid) || isOutstreamVideo(bid)) {
- normalizedBidRequest.video = getVideoTargetingParams(bid);
- }
- if (placementId) {
- normalizedBidRequest.placementId = placementId;
- } else {
- if (publisherId) {
- normalizedBidRequest.publisherId = publisherId;
- }
- if (placementKey) {
- normalizedBidRequest.placementKey = placementKey;
+const ID_REQUEST = {
+ buildServerRequests(requestObject, bidRequests, bidderRequest) {
+ const requests = [];
+ if (config.getConfig('improvedigital.singleRequest') === true) {
+ requestObject.imp = bidRequests.map((bidRequest) => this.buildImp(bidRequest));
+ requests[0] = this.formatRequest(requestObject, bidderRequest);
+ } else {
+ bidRequests.map((bidRequest) => {
+ const request = deepClone(requestObject);
+ request.id = bidRequest.bidId || getUniqueIdentifierStr();
+ request.imp = [this.buildImp(bidRequest)];
+ deepSetValue(request, 'source.tid', bidRequest.transactionId);
+ requests.push(this.formatRequest(request, bidderRequest));
+ });
}
- }
- if (keyValues) {
- normalizedBidRequest.keyValues = keyValues;
- }
+ return requests;
+ },
- if (config.getConfig('improvedigital.usePrebidSizes') === true && !isInstreamVideo(bid) && !isOutstreamVideo(bid) && bid.sizes && bid.sizes.length > 0) {
- normalizedBidRequest.format = bid.sizes;
- } else if (singleSizeFilter && singleSizeFilter.w && singleSizeFilter.h) {
- normalizedBidRequest.size = {};
- normalizedBidRequest.size.h = singleSizeFilter.h;
- normalizedBidRequest.size.w = singleSizeFilter.w;
- }
+ formatRequest(request, bidderRequest) {
+ return {
+ method: 'POST',
+ url: REQUEST_URL,
+ data: JSON.stringify(request),
+ bidderRequest
+ }
+ },
- if (bidId) {
- normalizedBidRequest.id = bidId;
- }
- if (adUnitId) {
- normalizedBidRequest.adUnitId = adUnitId;
- }
- if (transactionId) {
- normalizedBidRequest.transactionId = transactionId;
- }
- if (currency) {
- normalizedBidRequest.currency = currency;
- }
- // Floor
- let bidFloor = getBidFloor(bid);
- let bidFloorCur = null;
- if (!bidFloor) {
- bidFloor = getBidIdParameter('bidFloor', bid.params);
- bidFloorCur = getBidIdParameter('bidFloorCur', bid.params);
- }
- if (bidFloor) {
- normalizedBidRequest.bidFloor = bidFloor;
- normalizedBidRequest.bidFloorCur = bidFloorCur ? bidFloorCur.toUpperCase() : 'USD';
- }
- return normalizedBidRequest;
-}
+ buildImp(bidRequest) {
+ const imp = {
+ id: getBidIdParameter('bidId', bidRequest) || getUniqueIdentifierStr(),
+ secure: ID_UTIL.toBit(window.location.protocol === 'https:'),
+ };
-function getNormalizedNativeAd(rawNative) {
- const native = {};
- if (!rawNative || !isArray(rawNative.assets)) {
- return null;
- }
- // Assets
- rawNative.assets.forEach(asset => {
- if (asset.title) {
- native.title = asset.title.text;
- } else if (asset.data) {
- switch (asset.data.type) {
- case 1:
- native.sponsoredBy = asset.data.value;
- break;
- case 2:
- native.body = asset.data.value;
- break;
- case 3:
- native.rating = asset.data.value;
- break;
- case 4:
- native.likes = asset.data.value;
- break;
- case 5:
- native.downloads = asset.data.value;
- break;
- case 6:
- native.price = asset.data.value;
- break;
- case 7:
- native.salePrice = asset.data.value;
- break;
- case 8:
- native.phone = asset.data.value;
- break;
- case 9:
- native.address = asset.data.value;
- break;
- case 10:
- native.body2 = asset.data.value;
- break;
- case 11:
- native.displayUrl = asset.data.value;
- break;
- case 12:
- native.cta = asset.data.value;
- break;
- }
- } else if (asset.img) {
- switch (asset.img.type) {
- case 2:
- native.icon = {
- url: asset.img.url,
- width: asset.img.w,
- height: asset.img.h
- };
- break;
- case 3:
- native.image = {
- url: asset.img.url,
- width: asset.img.w,
- height: asset.img.h
- };
- break;
- }
+ // Floor
+ const bidFloor = this.getBidFloor(bidRequest) || getBidIdParameter('bidFloor', bidRequest.params);
+ if (bidFloor) {
+ const bidFloorCur = getBidIdParameter('bidFloorCur', bidRequest.params) || 'USD';
+ deepSetValue(imp, 'bidfloor', bidFloor);
+ deepSetValue(imp, 'bidfloorcur', bidFloorCur ? bidFloorCur.toUpperCase() : undefined);
}
- });
- // Trackers
- if (rawNative.eventtrackers) {
- native.impressionTrackers = [];
- rawNative.eventtrackers.forEach(tracker => {
- // Only handle impression event. Viewability events are not supported yet.
- if (tracker.event !== 1) return;
- switch (tracker.method) {
- case 1: // img
- native.impressionTrackers.push(tracker.url);
- break;
- case 2: // js
- // javascriptTrackers is a string. If there's more than one JS tracker in bid response, the last script will be used.
- native.javascriptTrackers = ``;
- break;
- }
- });
- } else {
- native.impressionTrackers = rawNative.imptrackers || [];
- native.javascriptTrackers = rawNative.jstracker;
- }
- if (rawNative.link) {
- native.clickUrl = rawNative.link.url;
- native.clickTrackers = rawNative.link.clicktrackers;
- }
- if (rawNative.privacy) {
- native.privacyLink = rawNative.privacy;
- }
- return native;
-}
-registerBidder(spec);
-export function ImproveDigitalAdServerJSClient(endPoint) {
- this.CONSTANTS = {
- AD_SERVER_BASE_URL: 'ice.360yield.com',
- END_POINT: endPoint || 'hb',
- AD_SERVER_URL_PARAM: 'jsonp=',
- CLIENT_VERSION: 'JS-6.4.0',
- MAX_URL_LENGTH: 2083,
- ERROR_CODES: {
- MISSING_PLACEMENT_PARAMS: 2,
- LIB_VERSION_MISSING: 3
- },
- RETURN_OBJ_TYPE: {
- DEFAULT: 0,
- URL_PARAMS_SPLIT: 1
+ const placementId = getBidIdParameter('placementId', bidRequest.params);
+ if (placementId) {
+ deepSetValue(imp, 'ext.bidder.placementId', placementId);
+ } else {
+ deepSetValue(imp, 'ext.bidder.publisherId', getBidIdParameter('publisherId', bidRequest.params));
+ deepSetValue(imp, 'ext.bidder.placementKey', getBidIdParameter('placementKey', bidRequest.params));
}
- };
- this.getErrorReturn = function(errorCode) {
- return {
- idMappings: {},
- requests: {},
- 'errorCode': errorCode
- };
- };
+ deepSetValue(imp, 'ext.bidder.keyValues', getBidIdParameter('keyValues', bidRequest.params) || undefined);
- this.createRequest = function(requestObject, requestParameters, extraRequestParameters) {
- if (!requestParameters.libVersion) {
- return this.getErrorReturn(this.CONSTANTS.ERROR_CODES.LIB_VERSION_MISSING);
- }
+ // Adding GPID
+ const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid') ||
+ deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot') ||
+ deepAccess(bidRequest, 'ortb2Imp.ext.data.adserver.adslot');
- requestParameters.returnObjType = requestParameters.returnObjType || this.CONSTANTS.RETURN_OBJ_TYPE.DEFAULT;
- requestParameters.adServerBaseUrl = 'https://' + (requestParameters.adServerBaseUrl || this.CONSTANTS.AD_SERVER_BASE_URL);
+ deepSetValue(imp, 'ext.gpid', gpid);
- let impressionObjects = [];
- let impressionObject;
- if (isArray(requestObject)) {
- for (let counter = 0; counter < requestObject.length; counter++) {
- impressionObject = this.createImpressionObject(requestObject[counter]);
- impressionObjects.push(impressionObject);
- }
- } else {
- impressionObject = this.createImpressionObject(requestObject);
- impressionObjects.push(impressionObject);
+ // Adding Interstitial Signal
+ if (deepAccess(bidRequest, 'ortb2Imp.instl')) {
+ imp.instl = 1;
}
- let returnIdMappings = true;
- if (requestParameters.returnObjType === this.CONSTANTS.RETURN_OBJ_TYPE.URL_PARAMS_SPLIT) {
- returnIdMappings = false;
+ const videoParams = deepAccess(bidRequest, 'mediaTypes.video');
+ if (videoParams) {
+ imp.video = this.buildVideoRequest(bidRequest);
+ deepSetValue(imp, 'ext.is_rewarded_inventory', (videoParams.rewarded === 1 || deepAccess(videoParams, 'ext.rewarded') === 1) || undefined);
}
- let returnObject = {};
- returnObject.requests = [];
- if (returnIdMappings) {
- returnObject.idMappings = [];
+ if (deepAccess(bidRequest, 'mediaTypes.banner')) {
+ imp.banner = this.buildBannerRequest(bidRequest);
}
- let errors = null;
- let baseUrl = `${requestParameters.adServerBaseUrl}/${this.CONSTANTS.END_POINT}?${this.CONSTANTS.AD_SERVER_URL_PARAM}`;
+ if (deepAccess(bidRequest, 'mediaTypes.native')) {
+ imp.native = this.buildNativeRequest(bidRequest);
+ }
- let bidRequestObject = {
- bid_request: this.createBasicBidRequestObject(requestParameters, extraRequestParameters)
- };
- for (let counter = 0; counter < impressionObjects.length; counter++) {
- impressionObject = impressionObjects[counter];
-
- if (impressionObject.errorCode) {
- errors = errors || [];
- errors.push({
- errorCode: impressionObject.errorCode,
- adUnitId: impressionObject.adUnitId
- });
- } else {
- if (returnIdMappings) {
- returnObject.idMappings.push({
- adUnitId: impressionObject.adUnitId,
- id: impressionObject.impressionObject.id
- });
- }
- bidRequestObject.bid_request.imp = bidRequestObject.bid_request.imp || [];
- bidRequestObject.bid_request.imp.push(impressionObject.impressionObject);
-
- let writeLongRequest = false;
- const outputUri = baseUrl + encodeURIComponent(JSON.stringify(bidRequestObject));
- if (outputUri.length > this.CONSTANTS.MAX_URL_LENGTH) {
- writeLongRequest = true;
- if (bidRequestObject.bid_request.imp.length > 1) {
- // Pop the current request and process it again in the next iteration
- bidRequestObject.bid_request.imp.pop();
- if (returnIdMappings) {
- returnObject.idMappings.pop();
- }
- counter--;
- }
- }
+ return imp;
+ },
- if (writeLongRequest ||
- !requestParameters.singleRequestMode ||
- counter === impressionObjects.length - 1) {
- returnObject.requests.push(this.formatRequest(requestParameters, bidRequestObject));
- bidRequestObject = {
- bid_request: this.createBasicBidRequestObject(requestParameters, extraRequestParameters)
- };
- }
- }
+ buildVideoRequest(bidRequest) {
+ const videoParams = deepClone(bidRequest.mediaTypes.video);
+ const videoImproveParams = deepClone(deepAccess(bidRequest, 'params.video', {}));
+ const video = {...videoParams, ...videoImproveParams};
+
+ if (Array.isArray(video.playerSize)) {
+ // Player size can be defined as [w, h] or [[w, h]]
+ const size = Array.isArray(video.playerSize[0]) ? video.playerSize[0] : video.playerSize;
+ video.w = size[0];
+ video.h = size[1];
}
+ video.placement = this.isOutstreamVideo(bidRequest) ? VIDEO_PARAMS.PLACEMENT_TYPE.OUTSTREAM : VIDEO_PARAMS.PLACEMENT_TYPE.INSTREAM;
- if (errors) {
- returnObject.errors = errors;
+ // Mimes is required
+ if (!video.mimes) {
+ video.mimes = VIDEO_PARAMS.DEFAULT_MIMES;
}
- return returnObject;
- };
+ // skip must be 0 or 1
+ if (video.skip !== 1) {
+ delete video.skipmin;
+ delete video.skipafter;
+ if (video.skip !== 0) {
+ logWarn(`video.skip: invalid value '${video.skip}'. Expected 0 or 1`);
+ delete video.skip;
+ }
+ }
- this.formatRequest = function(requestParameters, bidRequestObject) {
- switch (requestParameters.returnObjType) {
- case this.CONSTANTS.RETURN_OBJ_TYPE.URL_PARAMS_SPLIT:
- return {
- method: 'GET',
- url: `${requestParameters.adServerBaseUrl}/${this.CONSTANTS.END_POINT}`,
- data: `${this.CONSTANTS.AD_SERVER_URL_PARAM}${encodeURIComponent(JSON.stringify(bidRequestObject))}`
+ Object.keys(video).forEach(prop => {
+ if (VIDEO_PARAMS.SUPPORTED_PROPERTIES.indexOf(prop) === -1) delete video[prop];
+ });
+ return video;
+ },
+
+ buildBannerRequest(bidRequest) {
+ // Set the desired creative sizes
+ // Input Format: array of pairs, i.e. [[300, 250], [250, 250]]
+ // Unless improvedigital.usePrebidSizes == true, no sizes are sent to the server
+ // and the sizes defined in the server for the placement will be used
+ const banner = {};
+ if (config.getConfig('improvedigital.usePrebidSizes') === true && bidRequest.sizes) {
+ // Convert sizes from [x, y] to { w: x, h: y}
+ banner.format = bidRequest.sizes.map(sizePair => ({w: sizePair[0], h: sizePair[1]}));
+ }
+ return banner;
+ },
+
+ buildNativeRequest(bidRequest) {
+ const nativeParams = bidRequest.mediaTypes.native;
+ const request = {
+ assets: [],
+ }
+ for (let i of Object.keys(nativeParams)) {
+ const assetOrtbParams = NATIVE_DATA.ASSETS[i];
+ if (assetOrtbParams) {
+ const assetParams = nativeParams[i];
+ const asset = {
+ id: assetOrtbParams.id,
+ required: ID_UTIL.toBit(assetParams.required),
};
- default:
- const baseUrl = `${requestParameters.adServerBaseUrl}/` +
- `${this.CONSTANTS.END_POINT}?${this.CONSTANTS.AD_SERVER_URL_PARAM}`;
- return {
- url: baseUrl + encodeURIComponent(JSON.stringify(bidRequestObject))
+ switch (assetOrtbParams.assetType) {
+ case NATIVE_DATA.ASSET_TYPES.TITLE:
+ asset.title = {len: assetParams.len || assetOrtbParams.default.len};
+ break;
+ case NATIVE_DATA.ASSET_TYPES.DATA:
+ asset.data = cleanObj({type: assetOrtbParams.type, len: assetParams.len})
+ break;
+ case NATIVE_DATA.ASSET_TYPES.IMG:
+ asset.img = cleanObj({
+ type: assetOrtbParams.type,
+ w: deepAccess(assetParams, 'sizes.0'),
+ h: deepAccess(assetParams, 'sizes.1'),
+ wmin: deepAccess(assetParams, 'aspect_ratios.0.min_width'),
+ hmin: deepAccess(assetParams, 'aspect_ratios.0.min_height')
+ });
+ break;
+ default:
+ return;
}
- }
- };
-
- this.createBasicBidRequestObject = function(requestParameters, extraRequestParameters) {
- let impressionBidRequestObject = {};
- impressionBidRequestObject.secure = 1;
- if (requestParameters.requestId) {
- impressionBidRequestObject.id = requestParameters.requestId;
- } else {
- impressionBidRequestObject.id = getUniqueIdentifierStr();
- }
- if (requestParameters.domain) {
- impressionBidRequestObject.domain = requestParameters.domain;
- }
- if (requestParameters.page) {
- impressionBidRequestObject.page = requestParameters.page;
- }
- if (requestParameters.ref) {
- impressionBidRequestObject.ref = requestParameters.ref;
- }
- if (requestParameters.callback) {
- impressionBidRequestObject.callback = requestParameters.callback;
- }
- if (requestParameters.libVersion) {
- impressionBidRequestObject.version = requestParameters.libVersion + '-' + this.CONSTANTS.CLIENT_VERSION;
- }
- if (requestParameters.referrer) {
- impressionBidRequestObject.referrer = requestParameters.referrer;
- }
- if (requestParameters.gdpr || requestParameters.gdpr === 0) {
- impressionBidRequestObject.gdpr = requestParameters.gdpr;
- }
- if (requestParameters.usPrivacy) {
- impressionBidRequestObject.us_privacy = requestParameters.usPrivacy;
- }
- if (requestParameters.schain) {
- impressionBidRequestObject.schain = requestParameters.schain;
- }
- if (requestParameters.pagecat) {
- impressionBidRequestObject.pagecat = requestParameters.pagecat;
- }
- if (requestParameters.genre) {
- impressionBidRequestObject.genre = requestParameters.genre;
- }
- if (requestParameters.user) {
- impressionBidRequestObject.user = requestParameters.user;
- }
- if (extraRequestParameters) {
- for (let prop in extraRequestParameters) {
- impressionBidRequestObject[prop] = extraRequestParameters[prop];
+ request.assets.push(asset);
}
}
+ return { ver: NATIVE_DATA.VERSION, request: JSON.stringify(request) };
+ },
- if (requestParameters.coppa) {
- impressionBidRequestObject.coppa = 1;
- }
+ isOutstreamVideo(bidRequest) {
+ return deepAccess(bidRequest, 'mediaTypes.video.context') === 'outstream';
+ },
- return impressionBidRequestObject;
- };
+ getBidFloor(bidRequest) {
+ if (!isFn(bidRequest.getFloor)) {
+ return null;
+ }
+ const floor = bidRequest.getFloor({
+ currency: 'USD',
+ mediaType: '*',
+ size: '*'
+ });
+ if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') {
+ return floor.floor;
+ }
+ return null;
+ },
- this.createImpressionObject = function(placementObject) {
- let outputObject = {};
- let impressionObject = {};
- outputObject.impressionObject = impressionObject;
+ buildSiteOrApp(request, bidderRequest) {
+ const app = {};
+ const configAppSettings = config.getConfig('app') || {};
+ const fpdAppSettings = config.getConfig('ortb2.app') || {};
+ mergeDeep(app, configAppSettings, fpdAppSettings);
- if (placementObject.id) {
- impressionObject.id = placementObject.id;
+ if (Object.keys(app).length !== 0) {
+ request.app = app;
} else {
- impressionObject.id = getUniqueIdentifierStr();
- }
- if (placementObject.adTypes) {
- impressionObject.ad_types = placementObject.adTypes;
- }
- if (placementObject.adUnitId) {
- outputObject.adUnitId = placementObject.adUnitId;
- }
- if (placementObject.currency) {
- impressionObject.currency = placementObject.currency.toUpperCase();
- }
- if (placementObject.bidFloor) {
- impressionObject.bidfloor = placementObject.bidFloor;
- }
- if (placementObject.bidFloorCur) {
- impressionObject.bidfloorcur = placementObject.bidFloorCur.toUpperCase();
- }
- if (placementObject.placementId) {
- impressionObject.pid = placementObject.placementId;
- }
- if (placementObject.publisherId) {
- impressionObject.pubid = placementObject.publisherId;
- }
- if (placementObject.placementKey) {
- impressionObject.pkey = placementObject.placementKey;
- }
- if (placementObject.transactionId) {
- impressionObject.tid = placementObject.transactionId;
- }
- if (!isEmpty(placementObject.video)) {
- const video = Object.assign({}, placementObject.video);
- // skip must be 0 or 1
- if (video.skip !== 1) {
- delete video.skipmin;
- delete video.skipafter;
- if (video.skip !== 0) {
- logWarn(`video.skip: invalid value '${video.skip}'. Expected 0 or 1`);
- delete video.skip;
- }
- }
- if (!isEmpty(video)) {
- impressionObject.video = video;
+ const site = {};
+ const url = config.getConfig('pageUrl') || deepAccess(bidderRequest, 'refererInfo.referer');
+ if (url) {
+ site.page = url;
+ site.domain = parseUrl(url).hostname;
}
+ const configSiteSettings = config.getConfig('site') || {};
+ const fpdSiteSettings = config.getConfig('ortb2.site') || {};
+ mergeDeep(site, configSiteSettings, fpdSiteSettings);
+ request.site = site;
}
- if (placementObject.keyValues) {
- for (let key in placementObject.keyValues) {
- for (let valueCounter = 0; valueCounter < placementObject.keyValues[key].length; valueCounter++) {
- impressionObject.kvw = impressionObject.kvw || {};
- impressionObject.kvw[key] = impressionObject.kvw[key] || [];
- impressionObject.kvw[key].push(placementObject.keyValues[key][valueCounter]);
- }
+ },
+};
+
+const ID_RESPONSE = {
+ buildAd(bid, bidRequest, bidResponse) {
+ if (bidRequest.mediaTypes && Object.keys(bidRequest.mediaTypes).length === 1) {
+ if (deepAccess(bidRequest, 'mediaTypes.video')) {
+ this.buildVideoAd(bid, bidRequest, bidResponse);
+ } else if (deepAccess(bidRequest, 'mediaTypes.banner')) {
+ this.buildBannerAd(bid, bidRequest, bidResponse);
+ } else if (deepAccess(bidRequest, 'mediaTypes.native')) {
+ this.buildNativeAd(bid, bidRequest, bidResponse)
+ }
+ } else {
+ if (bidResponse.adm.search(/^ sizePair.length === 2 &&
- isInteger(sizePair[0]) &&
- isInteger(sizePair[1]) &&
- sizePair[0] >= 0 &&
- sizePair[1] >= 0)
- .map(sizePair => {
- return { w: sizePair[0], h: sizePair[1] }
- });
- if (format.length > 0) {
- impressionObject.banner.format = format;
+ buildBannerAd(bid, bidRequest, bidResponse) {
+ bid.mediaType = BANNER;
+ bid.ad = bidResponse.adm;
+ bid.width = bidResponse.w;
+ bid.height = bidResponse.h;
+ },
+
+ buildNativeAd(bid, bidRequest, bidResponse) {
+ bid.mediaType = NATIVE;
+ const nativeResponse = JSON.parse(bidResponse.adm);
+ const nativeAd = {
+ clickUrl: deepAccess(nativeResponse, 'link.url'),
+ clickTrackers: deepAccess(nativeResponse, 'link.clicktrackers'),
+ privacyLink: nativeResponse.privacy
+ }
+ // Trackers
+ if (nativeResponse.eventtrackers) {
+ nativeAd.impressionTrackers = [];
+ nativeResponse.eventtrackers.forEach(tracker => {
+ // Only handle impression event. Viewability events are not supported yet.
+ if (tracker.event !== 1) return;
+ switch (tracker.method) {
+ case 1: // img
+ nativeAd.impressionTrackers.push(tracker.url);
+ break;
+ case 2: // js
+ // javascriptTrackers is a string. If there's more than one JS tracker in bid response, the last script will be used.
+ nativeAd.javascriptTrackers = ``;
+ break;
+ }
+ });
+ } else {
+ nativeAd.impressionTrackers = nativeResponse.imptrackers || [];
+ nativeAd.javascriptTrackers = nativeResponse.jstracker;
+ }
+ nativeResponse.assets.map(asset => {
+ const assetParams = NATIVE_DATA.getAssetById(asset.id);
+ switch (assetParams.assetType) {
+ case NATIVE_DATA.ASSET_TYPES.TITLE:
+ nativeAd.title = asset.title.text;
+ break;
+ case NATIVE_DATA.ASSET_TYPES.DATA:
+ nativeAd[assetParams.name] = asset.data.value;
+ break;
+ case NATIVE_DATA.ASSET_TYPES.IMG:
+ nativeAd[assetParams.name] = {
+ url: asset.img.url,
+ width: asset.img.w,
+ height: asset.img.h,
+ };
+ break;
}
+ });
+ bid.native = nativeAd;
+ },
+};
+
+const ID_OUTSTREAM = {
+ RENDERER_URL: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js',
+ createRenderer(bidRequest) {
+ const renderer = Renderer.install({
+ id: bidRequest.adUnitCode,
+ url: this.RENDERER_URL,
+ config: deepAccess(bidRequest, 'renderer.options'),
+ adUnitCode: bidRequest.adUnitCode
+ });
+ try {
+ renderer.setRender(this.render);
+ } catch (err) {
+ logWarn('Prebid Error calling setRender on renderer', err);
}
+ return renderer;
+ },
+
+ render(bid) {
+ bid.renderer.push(() => {
+ window.ANOutstreamVideo.renderAd({
+ sizes: [bid.width, bid.height],
+ targetId: bid.adUnitCode,
+ adResponse: bid.adResponse,
+ rendererOptions: bid.renderer.getConfig()
+ }, ID_OUTSTREAM.handleRendererEvents.bind(null, bid));
+ });
+ },
+
+ handleRendererEvents(bid, id, eventName) {
+ bid.renderer.handleVideoEvent({ id, eventName });
+ },
+};
- if (!impressionObject.pid &&
- !impressionObject.pubid &&
- !impressionObject.pkey &&
- !(impressionObject.banner && impressionObject.banner.w && impressionObject.banner.h)) {
- outputObject.impressionObject = null;
- outputObject.errorCode = this.CONSTANTS.ERROR_CODES.MISSING_PLACEMENT_PARAMS;
+const ID_RAZR = {
+ RENDERER_URL: 'https://razr.improvedigital.com/renderer.js',
+ addBidData({bid, bidRequest}) {
+ if (this.isValidBid(bid)) {
+ bid.renderer = Renderer.install({
+ url: this.RENDERER_URL,
+ config: {bidRequest}
+ });
+ bid.renderer.setRender(this.render);
}
- return outputObject;
- };
-}
+ },
+
+ isValidBid(bid) {
+ return bid && /razr:\/\//.test(bid.ad);
+ },
+
+ render(bid) {
+ const {bidRequest} = bid.renderer.getConfig();
+
+ const payload = {
+ type: 'prebid',
+ bidRequest,
+ bid,
+ config: mergeDeep(
+ {},
+ config.getConfig('improvedigital.rendererConfig'),
+ deepAccess(bidRequest, 'params.rendererConfig')
+ )
+ };
+
+ const razr = window.razr = window.razr || {};
+ razr.queue = razr.queue || [];
+ razr.queue.push(payload);
+ }
+};
+
+const ID_UTIL = {
+ toBit(val) {
+ return val ? 1 : 0;
+ },
+};
diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js
index 64c276ce806..9dcc11f5aa1 100644
--- a/test/spec/modules/improvedigitalBidAdapter_spec.js
+++ b/test/spec/modules/improvedigitalBidAdapter_spec.js
@@ -1,14 +1,14 @@
import { expect } from 'chai';
-import { ImproveDigitalAdServerJSClient, spec } from 'modules/improvedigitalBidAdapter.js';
+import { spec } from 'modules/improvedigitalBidAdapter.js';
import { config } from 'src/config.js';
import * as utils from 'src/utils.js';
+import {BANNER, VIDEO} from '../../../src/mediaTypes';
describe('Improve Digital Adapter Tests', function () {
- const idClient = new ImproveDigitalAdServerJSClient('hb');
-
- const METHOD = 'GET';
- const URL = 'https://ice.360yield.com/hb';
- const PARAM_PREFIX = 'jsonp=';
+ const METHOD = 'POST';
+ const URL = 'https://ad.360yield.com/pb';
+ const INSTREAM_TYPE = 1;
+ const OUTSTREAM_TYPE = 3;
const simpleBidRequest = {
bidder: 'improvedigital',
@@ -22,10 +22,10 @@ describe('Improve Digital Adapter Tests', function () {
auctionId: '192721e36a0239',
mediaTypes: {
banner: {
- sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
+ sizes: [[300, 250], [160, 600]]
}
},
- sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
+ sizes: [[300, 250], [160, 600]]
};
const videoParams = {
@@ -53,7 +53,7 @@ describe('Improve Digital Adapter Tests', function () {
const multiFormatBidRequest = utils.deepClone(simpleBidRequest);
multiFormatBidRequest.mediaTypes = {
banner: {
- sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]]
+ sizes: [[300, 250], [160, 600]]
},
video: {
context: 'outstream',
@@ -145,66 +145,85 @@ describe('Improve Digital Adapter Tests', function () {
describe('buildRequests', function () {
it('should make a well-formed request objects', function () {
- const requests = spec.buildRequests([simpleBidRequest], bidderRequest);
- expect(requests).to.be.an('array');
- expect(requests.length).to.equal(1);
-
- const request = requests[0];
+ const getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
+ const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
+ expect(request).to.be.an('object');
expect(request.method).to.equal(METHOD);
expect(request.url).to.equal(URL);
expect(request.bidderRequest).to.deep.equal(bidderRequest);
- expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX);
-
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request).to.be.an('object');
- expect(params.bid_request.id).to.be.a('string');
- expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`);
- expect(params.bid_request.gdpr).to.not.exist;
- expect(params.bid_request.us_privacy).to.not.exist;
- expect(params.bid_request.schain).to.not.exist;
- expect(params.bid_request.user).to.not.exist;
- expect(params.bid_request.imp).to.deep.equal([
+
+ const payload = JSON.parse(request.data);
+ expect(payload).to.be.an('object');
+ expect(payload.id).to.be.a('string');
+ expect(payload.tmax).not.to.exist;
+ expect(payload.cur).to.be.an('array');
+ expect(payload.regs).to.not.exist;
+ expect(payload.schain).to.not.exist;
+ expect(payload.source).to.be.an('object');
+ expect(payload.device).to.be.an('object');
+ expect(payload.user).to.not.exist;
+ expect(payload.imp).to.deep.equal([
{
id: '33e9500b21129f',
- pid: 1053688,
- tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
- banner: {}
+ secure: 0,
+ ext: {
+ bidder: {
+ placementId: 1053688,
+ }
+ },
+ banner: {
+ format: [
+ {w: 300, h: 250},
+ {w: 160, h: 600},
+ ]
+ }
}
]);
+ getConfigStub.restore();
});
it('should make a well-formed request object for multi-format ad unit', function () {
- const requests = spec.buildRequests([multiFormatBidRequest], multiFormatBidderRequest);
- expect(requests).to.be.an('array');
- expect(requests.length).to.equal(1);
-
- const request = requests[0];
+ const getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
+ const request = spec.buildRequests([multiFormatBidRequest], multiFormatBidderRequest)[0];
+ expect(request).to.be.an('object');
expect(request.method).to.equal(METHOD);
expect(request.url).to.equal(URL);
expect(request.bidderRequest).to.deep.equal(multiFormatBidderRequest);
- expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX);
-
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request).to.be.an('object');
- expect(params.bid_request.id).to.be.a('string');
- expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`);
- expect(params.bid_request.gdpr).to.not.exist;
- expect(params.bid_request.us_privacy).to.not.exist;
- expect(params.bid_request.imp).to.deep.equal([
+
+ const payload = JSON.parse(request.data);
+ expect(payload).to.be.an('object');
+ expect(payload.imp).to.deep.equal([
{
id: '33e9500b21129f',
- pid: 1053688,
- tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
- banner: {}
+ secure: 0,
+ ext: {
+ bidder: {
+ placementId: 1053688,
+ }
+ },
+ video: {
+ placement: OUTSTREAM_TYPE,
+ w: 640,
+ h: 480,
+ mimes: ['video/mp4'],
+ },
+ banner: {
+ format: [
+ {w: 300, h: 250},
+ {w: 160, h: 600},
+ ]
+ }
}
]);
+ getConfigStub.restore();
});
it('should set placementKey and publisherId for smart tags', function () {
- const requests = spec.buildRequests([simpleSmartTagBidRequest], bidderRequest);
- const params = JSON.parse(decodeURIComponent(requests[0].data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].pubid).to.equal(1032);
- expect(params.bid_request.imp[0].pkey).to.equal('data_team_test_hb_smoke_test');
+ const payload = JSON.parse(spec.buildRequests([simpleSmartTagBidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].ext.bidder.publisherId).to.equal(1032);
+ expect(payload.imp[0].ext.bidder.placementKey).to.equal('data_team_test_hb_smoke_test');
});
it('should add keyValues', function () {
@@ -215,102 +234,92 @@ describe('Improve Digital Adapter Tests', function () {
]
};
bidRequest.params.keyValues = keyValues;
- const request = spec.buildRequests([bidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].kvw).to.deep.equal(keyValues);
+ const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].ext.bidder.keyValues).to.deep.equal(keyValues);
});
- it('should add single size filter', function () {
- const bidRequest = Object.assign({}, simpleBidRequest);
- const size = {
- w: 800,
- h: 600
- };
- bidRequest.params.size = size;
- const request = spec.buildRequests([bidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner).to.deep.equal(size);
- // When single size filter is set, format shouldn't be populated. This
- // is to maintain backward compatibily
- expect(params.bid_request.imp[0].banner.format).to.not.exist;
- });
+ // it('should add single size filter', function () {
+ // const bidRequest = Object.assign({}, simpleBidRequest);
+ // const size = {
+ // w: 800,
+ // h: 600
+ // };
+ // bidRequest.params.size = size;
+ // const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest).data);
+ // expect(payload.imp[0].banner).to.deep.equal(size);
+ // // When single size filter is set, format shouldn't be populated. This
+ // // is to maintain backward compatibily
+ // expect(payload.imp[0].banner.format).to.not.exist;
+ // });
it('should add currency', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const getConfigStub = sinon.stub(config, 'getConfig').returns('JPY');
- const request = spec.buildRequests([bidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].currency).to.equal('JPY');
+ const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.cur).to.deep.equal(['JPY']);
getConfigStub.restore();
});
it('should add bid floor', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
- let request = spec.buildRequests([bidRequest], bidderRequest)[0];
- let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
+ let payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
// Floor price currency shouldn't be populated without a floor price
- expect(params.bid_request.imp[0].bidfloorcur).to.not.exist;
+ expect(payload.imp[0].bidfloorcur).to.not.exist;
// Default floor price currency
bidRequest.params.bidFloor = 0.05;
- request = spec.buildRequests([bidRequest], bidderRequest)[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
- expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD');
+ payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].bidfloor).to.equal(0.05);
+ expect(payload.imp[0].bidfloorcur).to.equal('USD');
// Floor price currency
bidRequest.params.bidFloorCur = 'eUR';
- request = spec.buildRequests([bidRequest])[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
- expect(params.bid_request.imp[0].bidfloorcur).to.equal('EUR');
+ payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].bidfloor).to.equal(0.05);
+ expect(payload.imp[0].bidfloorcur).to.equal('EUR');
// getFloor defined -> use it over bidFloor
let getFloorResponse = { currency: 'USD', floor: 3 };
bidRequest.getFloor = () => getFloorResponse;
- request = spec.buildRequests([bidRequest])[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].bidfloor).to.equal(3);
- expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD');
+ payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].bidfloor).to.equal(3);
+ // expect(payload.imp[0].bidfloorcur).to.equal('USD');
});
it('should add GDPR consent string', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestGdpr)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.gdpr).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==');
- expect(params.bid_request.user.ext.consented_providers_settings.consented_providers).to.exist.and.to.deep.equal([1, 35, 41, 101]);
+ const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data);
+ expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1);
+ expect(payload.user.ext.consent).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==');
+ expect(payload.user.ext.consented_providers_settings.consented_providers).to.exist.and.to.deep.equal([1, 35, 41, 101]);
});
it('should add CCPA consent string', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], { uspConsent: '1YYY' })[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.us_privacy).to.equal('1YYY');
+ const request = spec.buildRequests([bidRequest], {...bidderRequest, ...{ uspConsent: '1YYY' }});
+ const payload = JSON.parse(request[0].data);
+ expect(payload.regs.ext.us_privacy).to.equal('1YYY');
});
it('should add referrer', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.referrer).to.equal('https://blah.com/test.html');
+ const payload = JSON.parse(request.data);
+ expect(payload.site.page).to.equal('https://blah.com/test.html');
});
it('should not add video params for banner', function () {
const bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.not.exist;
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video).to.not.exist;
});
- it('should add ad type for instream video', function () {
+ it('should add correct placement value for instream and outstream video', function () {
let bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
- bidRequest.mediaType = 'video';
- let request = spec.buildRequests([bidRequest], bidderRequest)[0];
- let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']);
- expect(params.bid_request.imp[0].video).to.not.exist;
+ let payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].video).to.not.exist;
bidRequest = JSON.parse(JSON.stringify(simpleBidRequest));
bidRequest.mediaTypes = {
@@ -319,32 +328,45 @@ describe('Improve Digital Adapter Tests', function () {
playerSize: [640, 480]
}
};
- request = spec.buildRequests([bidRequest], bidderRequest)[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']);
- expect(params.bid_request.imp[0].video).to.not.exist;
- });
-
- it('should not set ad type for outstream video', function() {
- const request = spec.buildRequests([outstreamBidRequest])[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].ad_types).to.not.exist;
- expect(params.bid_request.imp[0].video).to.not.exist;
- });
-
- it('should not set ad type for multi-format bids', function() {
- const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].ad_types).to.not.exist;
- expect(params.bid_request.imp[0].video).to.not.exist;
+ payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].video.placement).to.exist.and.equal(1);
+ bidRequest.mediaTypes.video.context = 'outstream';
+ payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data);
+ expect(payload.imp[0].video.placement).to.exist.and.equal(3);
});
it('should set video params for instream', function() {
const bidRequest = JSON.parse(JSON.stringify(instreamBidRequest));
+ delete bidRequest.mediaTypes.video.playerSize;
+ const videoParams = {
+ mimes: ['video/mp4'],
+ skip: 1,
+ skipmin: 5,
+ skipafter: 30,
+ minduration: 15,
+ maxduration: 60,
+ startdelay: 5,
+ minbitrate: 500,
+ maxbitrate: 2000,
+ w: 1024,
+ h: 640,
+ placement: INSTREAM_TYPE,
+ };
bidRequest.params.video = videoParams;
- const request = spec.buildRequests([bidRequest])[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
+ const request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video).to.deep.equal(videoParams);
+ });
+
+ it('should set video playerSize over video params', () => {
+ const bidRequest = JSON.parse(JSON.stringify(instreamBidRequest));
+ bidRequest.params.video = {
+ w: 1024, h: 640
+ }
+ const request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.h).equal(480);
+ expect(payload.imp[0].video.w).equal(640);
});
it('should set skip params only if skip=1', function() {
@@ -357,22 +379,28 @@ describe('Improve Digital Adapter Tests', function () {
}
bidRequest.params.video = videoTest;
let request = spec.buildRequests([bidRequest])[0];
- let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal(videoTest);
+ let payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.skip).to.equal(1);
+ expect(payload.imp[0].video.skipmin).to.equal(5);
+ expect(payload.imp[0].video.skipafter).to.equal(30);
// 0 - leave out skipmin and skipafter
videoTest.skip = 0;
bidRequest.params.video = videoTest;
request = spec.buildRequests([bidRequest])[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal({ skip: 0 });
+ payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.skip).to.equal(0);
+ expect(payload.imp[0].video.skipmin).to.not.exist;
+ expect(payload.imp[0].video.skipafter).to.not.exist;
// other
videoTest.skip = 'blah';
bidRequest.params.video = videoTest;
request = spec.buildRequests([bidRequest])[0];
- params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.not.exist;
+ payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.skip).to.not.exist;
+ expect(payload.imp[0].video.skipmin).to.not.exist;
+ expect(payload.imp[0].video.skipafter).to.not.exist;
});
it('should ignore invalid/unexpected video params', function() {
@@ -387,51 +415,36 @@ describe('Improve Digital Adapter Tests', function () {
videoTestInvParam.blah = 1;
bidRequest.params.video = videoTestInvParam;
let request = spec.buildRequests([bidRequest])[0];
- let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal(videoTest);
+ let payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.blah).not.to.exist;
});
it('should set video params for outstream', function() {
const bidRequest = JSON.parse(JSON.stringify(outstreamBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest])[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video).to.deep.equal({...{
+ mimes: ['video/mp4'],
+ placement: OUTSTREAM_TYPE,
+ w: bidRequest.mediaTypes.video.playerSize[0],
+ h: bidRequest.mediaTypes.video.playerSize[1],
+ },
+ ...videoParams});
});
-
+ //
it('should set video params for multi-format', function() {
const bidRequest = JSON.parse(JSON.stringify(multiFormatBidRequest));
bidRequest.params.video = videoParams;
const request = spec.buildRequests([bidRequest])[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].video).to.deep.equal(videoParams);
- });
-
- it('should not set Prebid sizes in bid request for instream video', function () {
- const getConfigStub = sinon.stub(config, 'getConfig');
- getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
- const request = spec.buildRequests([instreamBidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner.format).to.not.exist;
- getConfigStub.restore();
- });
-
- it('should not set Prebid sizes in bid request for outstream video', function () {
- const getConfigStub = sinon.stub(config, 'getConfig');
- getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
- const request = spec.buildRequests([outstreamBidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner.format).to.not.exist;
- getConfigStub.restore();
- });
-
- it('should not set Prebid sizes in multi-format bid request', function () {
- const getConfigStub = sinon.stub(config, 'getConfig');
- getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
- const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner.format).to.not.exist;
- getConfigStub.restore();
+ const payload = JSON.parse(request.data);
+ const testVideoParams = Object.assign({
+ placement: OUTSTREAM_TYPE,
+ w: 640,
+ h: 480,
+ mimes: ['video/mp4'],
+ }, videoParams);
+ expect(payload.imp[0].video).to.deep.equal(testVideoParams);
});
it('should add schain', function () {
@@ -439,8 +452,8 @@ describe('Improve Digital Adapter Tests', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
bidRequest.schain = schain;
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.schain).to.equal(schain);
+ const payload = JSON.parse(request.data);
+ expect(payload.source.ext.schain).to.equal(schain);
});
it('should add eids', function () {
@@ -455,8 +468,8 @@ describe('Improve Digital Adapter Tests', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
bidRequest.userId = userId;
const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.user).to.deep.equal(expectedUserObject);
+ const payload = JSON.parse(request.data);
+ expect(payload.user).to.deep.equal(expectedUserObject);
});
it('should return 2 requests', function () {
@@ -486,8 +499,8 @@ describe('Improve Digital Adapter Tests', function () {
const getConfigStub = sinon.stub(config, 'getConfig');
getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true);
const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner).to.deep.equal({
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner).to.deep.equal({
format: [
{ w: 300, h: 250 },
{ w: 160, h: 600 }
@@ -506,8 +519,8 @@ describe('Improve Digital Adapter Tests', function () {
};
bidRequest.params.size = size;
const request = spec.buildRequests([bidRequest], bidderRequest)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.imp[0].banner).to.deep.equal({
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner).to.deep.equal({
format: [
{ w: 300, h: 250 },
{ w: 160, h: 600 }
@@ -516,434 +529,396 @@ describe('Improve Digital Adapter Tests', function () {
getConfigStub.restore();
});
- it('should set pagecat and genre ➞ fpd:ortb2.site', function() {
- config.setConfig(JSON.parse('{"ortb2":{"site":{"cat":["IAB2"],"pagecat":["IAB2-2"],"content":{"genre":"Adventure"}}}}'));
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.pagecat).to.be.an('array');
- expect(params.bid_request.pagecat).to.deep.equal(['IAB2-2']);
- expect(params.bid_request.genre).to.be.a('string');
- expect(params.bid_request.genre).be.equal('Adventure');
- });
+ it('should set GPID and Instl Signal', function () {
+ const bidRequest = Object.assign({
+ ortb2Imp: {
+ instl: true,
+ ext: {
+ gpid: '/123/ID-FORMAT',
+ data: {
+ pbadslot: '/123/ID-FORMAT-PBADSLOT',
+ adserver: {
+ adslot: '/123/ID-FORMAT-ADSERVER-PB-ADSLOT',
+ }
+ }
+ },
+ }
+ }, simpleBidRequest);
+ let request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT');
+ expect(payload.imp[0].instl).to.equal(1);
- it('should not set pagecat and genre when malformed data provided ➞ fpd:ortb2.site', function() {
- config.setConfig(JSON.parse('{"ortb2":{"site":{"pagecat":"IAB2-2","content":{"genre":["Adventure"]}}}}'));
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.pagecat).does.not.exist;
- expect(params.bid_request.genre).does.not.exist;
+ delete bidRequest.ortb2Imp.ext.gpid;
+ request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT-PBADSLOT');
+
+ delete bidRequest.ortb2Imp.ext.data.pbadslot;
+ request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT-ADSERVER-PB-ADSLOT');
+
+ delete bidRequest.ortb2Imp.ext.data.adserver;
+ delete bidRequest.ortb2Imp.instl;
+ request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.imp[0].ext.gpid).to.not.exist;
+ expect(payload.imp[0].instl).to.not.exist;
});
- it('should use cat when pagecat not available ➞ fpd:ortb2.site', function() {
- config.setConfig(JSON.parse('{"ortb2":{"site":{"cat":["IAB2"]}}}'));
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.pagecat).to.be.an('array');
- expect(params.bid_request.pagecat).to.deep.equal(['IAB2']);
+ it('should not set site when app is defined in FPD', function () {
+ const getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('ortb2.app').returns({ content: 'XYZ' });
+ let request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.site).does.not.exist;
+ expect(payload.app).does.exist;
+ expect(payload.app.content).does.exist.and.equal('XYZ');
+ getConfigStub.restore();
});
- it('should format pagecat correctly ➞ fpd:ortb2.site', function() {
- config.setConfig(JSON.parse('{"ortb2":{"site":{"cat":["IAB2", ["IAB-1"], "IAB3", 123, ""]}}}'));
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.pagecat).to.be.an('array');
- expect(params.bid_request.pagecat).to.deep.equal([
- 'IAB2',
- 'IAB3'
- ]
- );
+ it('should not set site when app is defined in CONFIG', function () {
+ const getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('app').returns({ content: 'XYZ' });
+ let request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.site).does.not.exist;
+ expect(payload.app).does.exist;
+ expect(payload.app.content).does.exist.and.equal('XYZ');
+ getConfigStub.restore();
});
- it('should set coppa', function() {
- sinon.stub(config, 'getConfig')
- .withArgs('coppa')
- .returns(true);
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.coppa).to.equal(1);
+ it('should set correct site params', function () {
+ let getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('site').returns({
+ content: 'XYZ',
+ page: 'https://improveditigal.com/',
+ domain: 'improveditigal.com'
+ });
+ let request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.site.content).does.exist.and.equal('XYZ');
+ expect(payload.site.page).does.exist.and.equal('https://improveditigal.com/');
+ expect(payload.site.domain).does.exist.and.equal('improveditigal.com');
+ getConfigStub.reset();
+
+ request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.site.content).does.not.exist;
+ expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html');
+ expect(payload.site.domain).does.exist.and.equal('blah.com');
+
+ getConfigStub.withArgs('ortb2.site').returns({
+ content: 'ZZZ',
+ });
+ request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.site.content).does.exist.and.equal('ZZZ');
+ expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html');
+ expect(payload.site.domain).does.exist.and.equal('blah.com');
+ getConfigStub.restore();
+ });
- config.getConfig.restore();
+ it('should set pageUrl as site param', function () {
+ let getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('pageUrl').returns('https://improvidigital.com/test-page');
+ let request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.site.page).does.exist.and.equal('https://improvidigital.com/test-page');
+ expect(payload.site.domain).does.exist.and.equal('improvidigital.com');
+ getConfigStub.reset();
+
+ getConfigStub.withArgs('pageUrl').returns(undefined);
+ request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0];
+ payload = JSON.parse(request.data);
+ expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html');
+ expect(payload.site.domain).does.exist.and.equal('blah.com');
+ getConfigStub.restore();
});
- it('should undefined coppa', function() {
- const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
- const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
- expect(params.bid_request.coppa).to.equal(undefined);
+ it('should set site when app not available', function () {
+ const getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.withArgs('app').returns(undefined);
+ let request = spec.buildRequests([simpleBidRequest], bidderRequest)[0];
+ let payload = JSON.parse(request.data);
+ expect(payload.site).does.exist;
+ expect(payload.app).does.not.exist;
+ getConfigStub.restore();
});
});
const serverResponse = {
'body': {
- 'id': '687a06c541d8d1',
- 'site_id': 191642,
- 'bid': [
+ 'id': '99f9a9e6-5126-425b-822c-8b4edad2a719',
+ 'cur': 'EUR',
+ 'seatbid': [
{
- 'isNet': false,
- 'id': '33e9500b21129f',
- 'advid': '5279',
- 'price': 1.45888594164456,
- 'nurl': 'https://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
- 'h': 290,
- 'pid': 1053688,
- 'sync': [
- 'https://link1',
- 'https://link2'
- ],
- 'crid': '422031',
- 'w': 600,
- 'cid': '99006',
- 'adm': 'document.writeln(\"<\\/a>\");document.writeln(\"<\\/improvedigital_ad_output_information>\");'
- }
- ],
- 'debug': ''
- }
- };
-
- const serverResponseRazr = {
- 'body': {
- 'id': '687a06c541d8d1',
- 'site_id': 191642,
- 'bid': [
- {
- 'isNet': false,
- 'id': '33e9500b21129f',
- 'advid': '5279',
- 'price': 1.45888594164456,
- 'nurl': 'https://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
- 'h': 290,
- 'pid': 1053688,
- 'sync': [
- 'https://link1',
- 'https://link2'
+ 'bid': [
+ {
+ 'ext': {
+ 'improvedigital': {
+ 'line_item_id': 320896,
+ 'bidder_id': 0,
+ 'brand_name': '',
+ 'buying_type': 'classic',
+ 'agency_id': '0'
+ }
+ },
+ 'exp': 120,
+ 'crid': '510265',
+ 'price': 1.9200543539802946,
+ 'id': '35adfe19-d6e9-46b9-9f7d-20da7026b965',
+ 'w': 728,
+ 'impid': '33e9500b21129f',
+ 'h': 90,
+ 'adm': '',
+ 'cid': '123159'
+ }
],
- 'crid': '422031',
- 'w': 600,
- 'cid': '99006',
- 'adm': 'document.writeln("',
- privacy: 'https://www.myprivacyurl.com'
- }
+ 'crid': '544456',
+ 'exp': 120,
+ 'id': '52098fad-20c1-476b-a4fa-41e275e5a4a5',
+ 'price': 1.8600000000000003,
+ 'adm': "{\"ver\":\"1.1\",\"imptrackers\":[\"https://secure.adnxs.com/imptr?id=52311&t=2\",\"https://euw-ice.360yield.com/imp_pixel?ic=hcUBlCANx1FabHBf6FR2gC7UO4xEyXahdZAn0-B5qL-bb3A74BJ1smyWIyW7IWcC0SOjSXzVpevTHXxTqJ.sf.Qhahyy6tSo.0j1QWfXlH8sM4-8vKWjMjw-x.IrJJNlwkQ0s1CdwcwTefcLXm5l2E-W19VhACuV7f3mgrZMNjiSw.SjJAfyPC3SIyAMRjYfj53UmjriQ46T7lhmkqxK8wHmksYCdbZc3PZESk8NWl28sxdjNvnYYCFMcJbeav.LOLabyTXfwy-1cEPbQs.IKMRZIKaqccTDPV3wOtzbNv0jQzatd3Nnv-PGFQcjQ-GW3i27W04Fws4kodpFSn-B6VwZAjzLzoyd5gBncyRnAyCplEbgHU5sZ1IyKHWjgCl3ZtRIK5vqrRD5D-xqgSnOi7-phG.CqZWDZ4bMDSfQg2ZnbvUTyGKcEl0WR59dW5izTMV4Fjizcrvr5T-t.zMbGwz.hGnmLIyhTqh.IcwW.GiDLVExlDlix5S1LXIWVsSyrQ==\"],\"assets\":[{\"id\":1,\"data\":{\"value\":\"ImproveDigital\",\"type\":1}},{\"id\":3,\"data\":{\"value\":\"Test content.\",\"type\":2}},{\"id\":0,\"title\":{\"text\":\"Sample Prebid Test Title\"}}],\"link\":{\"url\":\"https://euw-ice.360yield.com/click/hcUBlHOV7YhVse8RyBa0ajjyPa9Vt17e4g-1m3cRj3E67vq-RYux.SiUeAmBfNBcoOqkUc6A15AWmi4yFu5K-BdkaYjildyyk7fNLyR6hWr411kv4vrFwm5jrIBceuHS6K8oN69f.uCo8zGTdR2TbSlldwcpahQPlufZU.6VaMsu4IC53uEiUT5vb7kAw6TTlxuGBNq6zaGryiWEV2.N3YYJDTyYPh8tv-ZFyeFZFm0Gnjv.xWbC.70JcRUVU9UelQaPsTpTWYTXBhJt84YJUw1-GNtaLNVLSjjZbVoA2fsMti5p6OBmF.7u39on2OPgvseIkSmge7Pqg63pRqdP75hp.DAEk6OkcN1jGnwP2DSbvpaSbin5lVqjfO0B-wnQgfQTCUtM5v4JmkNweLhUf9Q-x.nPKLW5SccEk9ZFXzY2-1wpT3PWm8Tix3NRscLPZub9wHzL..pl6ip8cQ9hp16UjwT4H6RMAxL0R7bl-h2pAicGAzYmuO7ntRESKUoIWA==//http%3A%2F%2Fquantum-advertising.com%2Ffr%2F\"},\"jstracker\":\"\"}",
+ 'impid': '2d7a7db325c6f',
+ 'cid': '196108'
+ }
+ ],
+ 'seat': 'improvedigital'
}
- ],
- debug: ''
+ ]
}
};
const serverResponseVideo = {
'body': {
- 'id': '687a06c541d8d1',
- 'site_id': 191642,
- 'bid': [
+ 'id': '8ed20675-8934-430c-b645-1ccd17b35839',
+ 'cur': 'EUR',
+ 'seatbid': [
{
- 'isNet': false,
- 'id': '33e9500b21129f',
- 'advid': '5279',
- 'price': 1.45888594164456,
- 'nurl': 'http://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=',
- 'h': 290,
- 'pid': 1053688,
- 'sync': [
- 'http://link1',
- 'http://link2'
+ 'bid': [
+ {
+ 'ext': {
+ 'improvedigital': {
+ 'line_item_id': 321329,
+ 'bidder_id': 0,
+ 'brand_name': '',
+ 'buying_type': 'classic',
+ 'agency_id': '0'
+ }
+ },
+ 'exp': 120,
+ 'crid': '484367',
+ 'price': 9.600271769901472,
+ 'id': 'b131fd7b-5759-4b72-800e-60e69291e7d9',
+ 'adomain': [
+ 'improvedigital.com'
+ ],
+ 'impid': '33e9500b21129f',
+ 'adm': '',
+ 'w': 640,
+ 'h': 480,
+ 'cid': '123159'
+ }
],
- 'crid': '422031',
- 'w': 600,
- 'cid': '99006',
- 'adm': '',
- 'ad_type': 'video'
+ 'seat': 'improvedigital'
}
],
- 'debug': ''
}
};
- const nativeEventtrackers = [
- {
- event: 1,
- method: 1,
- url: 'https://www.mytracker.com/imptracker'
- },
- {
- event: 1,
- method: 2,
- url: 'https://www.mytracker.com/tracker.js'
+ const serverResponseRazr = {
+ body: {
+ 'id': '2adac6a5fe04df',
+ 'cur': 'EUR',
+ 'ext': {
+ 'improvedigital': {
+ 'sync': [
+ 'https://d5p.de17a.com/getuid/improve_digital?publisher_user_id=ce26f11e-567a-4eb7-bf94-51752e293ca5&publisher_dsp_id=61&publisher_call_type=redirect&gdpr=1&gdpr_consent=CPU22FrPU22FrAcABBENCDCsAP_AAH_AAChQIltf_X__b3_j-_5_f_t0eY1P9_7_v-0zjhfdt-8N3f_X_L8X42M7vF36pq4KuR4Eu3LBIQdlHOHcTUmw6okVrzPsbk2cr7NKJ7PEmnMbO2dYGH9_n93TuZKY7______z_v-v_v____f_7-3_3__5_3---_e_V_99zLv9____39nP___9v-_9_____4IhgEmGpeQBdmWODJtGlUKIEYVhIdAKACigGFoisIHVwU7K4CfUELABCagJwIgQYgowYBAAIJAEhEQEgB4IBEARAIAAQAqwEIACNgEFgBYGAQACgGhYgRQBCBIQZHBUcpgQFSLRQT2ViCUHexphCGWeBFAo_oqEBGs0QLAyEhYOY4AkBLxZIHmKF8gAAAAA.f_gAD_gAAAAA&publisher_redirecturl=https://euw-ice.360yield.com/match'
+ ]
+ }
+ },
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'ext': {
+ 'improvedigital': {
+ 'line_item_id': 410573,
+ 'bidder_id': 0,
+ 'brand_name': '',
+ 'buying_type': 'classic',
+ 'agency_id': '0'
+ }
+ },
+ 'exp': 120,
+ 'crid': '544063',
+ 'price': 1.9199364935359489,
+ 'id': '1fcf4dd8-a783-48ed-b59c-8fc8eeccb024',
+ 'adomain': [
+ 'improvedigital.com'
+ ],
+ 'w': 970,
+ 'impid': '33e9500b21129f',
+ 'h': 250,
+ 'adm': '\n\n\n\n\n\n\n\n',
+ 'cid': '187354'
+ }
+ ],
+ 'seat': 'improvedigital'
+ }
+ ]
}
- ];
+ };
describe('interpretResponse', function () {
const expectedBid = [
{
- 'ad': '',
- 'creativeId': '422031',
- 'cpm': 1.45888594164456,
- 'currency': 'USD',
- 'height': 290,
- 'mediaType': 'banner',
- 'netRevenue': false,
- 'requestId': '33e9500b21129f',
- 'ttl': 300,
- 'width': 600
+ requestId: '33e9500b21129f',
+ cpm: 1.9200543539802946,
+ currency: 'EUR',
+ width: 728,
+ height: 90,
+ ttl: 300,
+ ad: '',
+ creativeId: '510265',
+ dealId: 320896,
+ netRevenue: false,
+ mediaType: BANNER,
+ meta: {
+ advertiserDomains: []
+ }
}
];
const expectedTwoBids = [
expectedBid[0],
{
- 'ad': '',
- 'creativeId': '422033',
- 'cpm': 1.23,
- 'currency': 'USD',
- 'height': 400,
- 'mediaType': 'banner',
- 'netRevenue': true,
- 'requestId': '1234',
- 'ttl': 300,
- 'width': 700
- }
- ];
-
- const expectedBidNative = [
- {
- mediaType: 'native',
- creativeId: '422031',
- cpm: 1.45888594164456,
- currency: 'USD',
- height: 290,
- netRevenue: false,
requestId: '33e9500b21129f',
+ cpm: 1.9200543539802946,
+ currency: 'EUR',
+ width: 300,
+ height: 250,
ttl: 300,
- width: 600,
- native: {
- title: 'Native title',
- body: 'Native body',
- body2: 'body2',
- cta: 'Do it',
- sponsoredBy: 'Improve Digital',
- rating: '4',
- likes: '10105',
- downloads: '150000',
- price: '3.99',
- salePrice: '4.49',
- phone: '(123) 456-7890',
- address: '123 Main Street, Anywhere USA',
- displayUrl: 'https://myurl.com',
- icon: {
- url: 'https://blah.com/icon.jpg',
- height: 30,
- width: 40
- },
- image: {
- url: 'https://blah.com/image.jpg',
- height: 200,
- width: 800
- },
- clickUrl: 'https://advertiser.com',
- clickTrackers: ['https://click.tracker.com/click?impid=123'],
- impressionTrackers: [
- 'https://ice.360yield.com/imp_pixel?ic=wVm',
- 'https://imptrack1.com',
- 'https://imptrack2.com'
- ],
- javascriptTrackers: '',
- privacyLink: 'https://www.myprivacyurl.com'
+ ad: '',
+ creativeId: '479163',
+ dealId: 320896,
+ netRevenue: false,
+ mediaType: BANNER,
+ meta: {
+ advertiserDomains: []
}
}
];
const expectedBidInstreamVideo = [
{
- 'vastXml': '',
- 'creativeId': '422031',
- 'cpm': 1.45888594164456,
- 'currency': 'USD',
- 'height': 290,
- 'mediaType': 'video',
- 'netRevenue': false,
- 'requestId': '33e9500b21129f',
- 'ttl': 300,
- 'width': 600
+ requestId: '33e9500b21129f',
+ cpm: 9.600271769901472,
+ currency: 'EUR',
+ ttl: 300,
+ vastXml: '',
+ creativeId: '484367',
+ dealId: 321329,
+ netRevenue: false,
+ mediaType: VIDEO,
+ meta: {
+ advertiserDomains: ['improvedigital.com'],
+ }
}
];
const expectedBidOutstreamVideo = utils.deepClone(expectedBidInstreamVideo);
expectedBidOutstreamVideo[0].adResponse = {
- content: expectedBidOutstreamVideo[0].vastXml,
- height: expectedBidOutstreamVideo[0].height,
- width: expectedBidOutstreamVideo[0].width
+ content: expectedBidOutstreamVideo[0].vastXml
};
it('should return a well-formed display bid', function () {
@@ -965,50 +940,35 @@ describe('Improve Digital Adapter Tests', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
let bids;
- delete response.body.bid[0].lid;
- response.body.bid[0].buying_type = 'deal_id';
+ delete response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id;
+ response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'deal_id';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
- response.body.bid[0].lid = 268515;
- delete response.body.bid[0].buying_type;
+ response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515;
+ delete response.body.seatbid[0].bid[0].ext.improvedigital.buying_type;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
- response.body.bid[0].lid = 268515;
- response.body.bid[0].buying_type = 'rtb';
+ response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515;
+ response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'rtb';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.not.exist;
- response.body.bid[0].lid = 268515;
- response.body.bid[0].buying_type = 'classic';
+ response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515;
+ response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'classic';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.equal(268515);
- response.body.bid[0].lid = 268515;
- response.body.bid[0].buying_type = 'deal_id';
+ response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515;
+ response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'deal_id';
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].dealId).to.equal(268515);
-
- response.body.bid[0].lid = [ 268515, 12456, 34567 ];
- response.body.bid[0].buying_type = 'deal_id';
- bids = spec.interpretResponse(response, {bidderRequest});
- expect(bids[0].dealId).to.not.exist;
-
- response.body.bid[0].lid = [ 268515, 12456, 34567 ];
- response.body.bid[0].buying_type = [ 'deal_id', 'classic' ];
- bids = spec.interpretResponse(response, {bidderRequest});
- expect(bids[0].dealId).to.not.exist;
-
- response.body.bid[0].lid = [ 268515, 12456, 34567 ];
- response.body.bid[0].buying_type = [ 'rtb', 'deal_id', 'deal_id' ];
- bids = spec.interpretResponse(response, {bidderRequest});
- expect(bids[0].dealId).to.equal(12456);
});
it('should set currency', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
- response.body.bid[0].currency = 'eur';
+ response.body.cur = 'eur';
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].currency).to.equal('EUR');
});
@@ -1018,35 +978,35 @@ describe('Improve Digital Adapter Tests', function () {
let bids;
// Price missing or 0
- response.body.bid[0].price = 0;
+ response.body.seatbid[0].bid[0].price = 0;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
- delete response.body.bid[0].price;
+ delete response.body.seatbid[0].bid[0];
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
- response.body.bid[0].price = null;
+ response.body.seatbid[0].bid[0] = [];
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
// errorCode present
response = JSON.parse(JSON.stringify(serverResponse));
- response.body.bid[0].errorCode = undefined;
+ response.body.seatbid[0].bid[0].errorCode = undefined;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
// adm and native missing
response = JSON.parse(JSON.stringify(serverResponse));
- delete response.body.bid[0].adm;
+ delete response.body.seatbid[0].bid[0].adm;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
- response.body.bid[0].adm = null;
+ response.body.seatbid[0].bid[0].adm = null;
bids = spec.interpretResponse(response, {bidderRequest});
expect(bids).to.deep.equal([]);
});
it('should set netRevenue', function () {
const response = JSON.parse(JSON.stringify(serverResponse));
- response.body.bid[0].isNet = true;
+ response.body.seatbid[0].bid[0].ext.improvedigital.is_net = true;
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].netRevenue).to.equal(true);
});
@@ -1054,30 +1014,31 @@ describe('Improve Digital Adapter Tests', function () {
it('should set advertiserDomains', function () {
const adomain = ['domain.com'];
const response = JSON.parse(JSON.stringify(serverResponse));
- response.body.bid[0].adomain = adomain;
+ response.body.seatbid[0].bid[0].adomain = adomain;
const bids = spec.interpretResponse(response, {bidderRequest});
expect(bids[0].meta.advertiserDomains).to.equal(adomain);
});
-
+ //
// Native ads
it('should return a well-formed native ad bid', function () {
- let bids = spec.interpretResponse(serverResponseNative, {bidderRequest});
- expect(bids[0].ortbNative).to.deep.equal(serverResponseNative.body.bid[0].native);
- delete bids[0].ortbNative;
- expect(bids).to.deep.equal(expectedBidNative);
-
- // eventtrackers
- const response = JSON.parse(JSON.stringify(serverResponseNative));
- const expectedBids = JSON.parse(JSON.stringify(expectedBidNative));
- response.body.bid[0].native.eventtrackers = nativeEventtrackers;
- expectedBids[0].native.impressionTrackers = [
- 'https://ice.360yield.com/imp_pixel?ic=wVm',
- 'https://www.mytracker.com/imptracker'
- ];
- expectedBids[0].native.javascriptTrackers = '';
- bids = spec.interpretResponse(response, {bidderRequest});
- delete bids[0].ortbNative;
- expect(bids).to.deep.equal(expectedBids);
+ const nativeBidderRequest = JSON.parse(JSON.stringify(bidderRequest));
+ nativeBidderRequest.bids[0].bidId = '2d7a7db325c6f';
+ delete nativeBidderRequest.bids[0].mediaTypes.banner;
+ nativeBidderRequest.bids[0].mediaTypes.native = {};
+ const bids = spec.interpretResponse(serverResponseNative, {bidderRequest: nativeBidderRequest});
+ // Verify Native Response
+ expect(bids[0].native).to.exist;
+ const nativeBid = bids[0].native;
+ const nativeResp = JSON.parse(serverResponseNative.body.seatbid[0].bid[0].adm);
+ // Verify Native Response
+ expect(nativeBid.clickUrl).to.exist.and.equal(nativeResp.link.url);
+ expect(nativeBid.impressionTrackers).to.exist.and.deep.equal(nativeResp.imptrackers);
+ expect(nativeBid.javascriptTrackers).to.exist.and.deep.equal(nativeResp.jstracker);
+
+ // Verify Assets
+ expect(nativeBid.title).to.exist.and.equal('Sample Prebid Test Title');
+ expect(nativeBid.sponsoredBy).to.exist.and.equal('ImproveDigital');
+ expect(nativeBid.body).to.exist.and.equal('Test content.');
});
// Video