diff --git a/modules/openwebBidAdapter.js b/modules/openwebBidAdapter.js
index 547447039da..39bd50f61a9 100644
--- a/modules/openwebBidAdapter.js
+++ b/modules/openwebBidAdapter.js
@@ -1,249 +1,487 @@
-import {deepAccess, flatten, isArray, isNumber, parseSizesInput} from '../src/utils.js';
+import {
+ logWarn,
+ logInfo,
+ isArray,
+ isFn,
+ deepAccess,
+ isEmpty,
+ contains,
+ triggerPixel,
+ isInteger,
+ getBidIdParameter,
+ getDNT
+} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
-import {ADPOD, BANNER, VIDEO} from '../src/mediaTypes.js';
+import {BANNER, VIDEO} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
-import {find} from '../src/polyfill.js';
-import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js';
-const ENDPOINT = 'https://ghb.spotim.market/v2/auction';
+const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
const BIDDER_CODE = 'openweb';
-const DISPLAY = 'display';
-const syncsCache = {};
+const ADAPTER_VERSION = '6.0.0';
+const TTL = 360;
+const DEFAULT_CURRENCY = 'USD';
+const SELLER_ENDPOINT = 'https://hb.openwebmp.com/';
+const MODES = {
+ PRODUCTION: 'hb-multi',
+ TEST: 'hb-multi-test'
+}
+const SUPPORTED_SYNC_METHODS = {
+ IFRAME: 'iframe',
+ PIXEL: 'pixel'
+}
export const spec = {
code: BIDDER_CODE,
gvlid: 280,
- supportedMediaTypes: [VIDEO, BANNER, ADPOD],
- isBidRequestValid: function (bid) {
- return isNumber(deepAccess(bid, 'params.aid'));
- },
- getUserSyncs: function (syncOptions, serverResponses) {
- const syncs = [];
+ version: ADAPTER_VERSION,
+ supportedMediaTypes: SUPPORTED_AD_TYPES,
+ isBidRequestValid: function (bidRequest) {
+ if (!bidRequest.params) {
+ logWarn('no params have been set to OpenWeb adapter');
+ return false;
+ }
- function addSyncs(bid) {
- const uris = bid.cookieURLs;
- const types = bid.cookieURLSTypes || [];
+ if (!bidRequest.params.org) {
+ logWarn('org is a mandatory param for OpenWeb adapter');
+ return false;
+ }
- if (Array.isArray(uris)) {
- uris.forEach((uri, i) => {
- const type = types[i] || 'image';
+ return true;
+ },
+ buildRequests: function (validBidRequests, bidderRequest) {
+ const combinedRequestsObject = {};
- if ((!syncOptions.pixelEnabled && type === 'image') ||
- (!syncOptions.iframeEnabled && type === 'iframe') ||
- syncsCache[uri]) {
- return;
- }
+ // use data from the first bid, to create the general params for all bids
+ const generalObject = validBidRequests[0];
+ const testMode = generalObject.params.testMode;
- syncsCache[uri] = true;
- syncs.push({
- type: type,
- url: uri
- })
- })
- }
+ combinedRequestsObject.params = generateGeneralParams(generalObject, bidderRequest);
+ combinedRequestsObject.bids = generateBidsParams(validBidRequests, bidderRequest);
+
+ return {
+ method: 'POST',
+ url: getEndpoint(testMode),
+ data: combinedRequestsObject
}
+ },
+ interpretResponse: function ({body}) {
+ const bidResponses = [];
- if (syncOptions.pixelEnabled || syncOptions.iframeEnabled) {
- isArray(serverResponses) && serverResponses.forEach((response) => {
- if (response.body) {
- if (isArray(response.body)) {
- response.body.forEach(b => {
- addSyncs(b);
- })
- } else {
- addSyncs(response.body)
+ if (body && body.bids && body.bids.length) {
+ body.bids.forEach(adUnit => {
+ const bidResponse = {
+ requestId: adUnit.requestId,
+ cpm: adUnit.cpm,
+ currency: adUnit.currency || DEFAULT_CURRENCY,
+ width: adUnit.width,
+ height: adUnit.height,
+ ttl: adUnit.ttl || TTL,
+ creativeId: adUnit.requestId,
+ netRevenue: adUnit.netRevenue || true,
+ nurl: adUnit.nurl,
+ mediaType: adUnit.mediaType,
+ meta: {
+ mediaType: adUnit.mediaType
}
+ };
+
+ if (adUnit.mediaType === VIDEO) {
+ bidResponse.vastXml = adUnit.vastXml;
+ } else if (adUnit.mediaType === BANNER) {
+ bidResponse.ad = adUnit.ad;
}
- })
- }
- return syncs;
- },
- /**
- * Make a server request from the list of BidRequests
- * @param bidRequests
- * @param adapterRequest
- */
- buildRequests: function (bidRequests, adapterRequest) {
- const { tag, bids } = bidToTag(bidRequests, adapterRequest);
- return [{
- data: Object.assign({}, tag, { BidRequests: bids }),
- adapterRequest,
- method: 'POST',
- url: ENDPOINT
- }];
- },
- /**
- * Unpack the response from the server into a list of bids
- * @param serverResponse
- * @param bidderRequest
- * @return {Bid[]} An array of bids which were nested inside the server
- */
- interpretResponse: function (serverResponse, { adapterRequest }) {
- serverResponse = serverResponse.body;
- let bids = [];
+ if (adUnit.adomain && adUnit.adomain.length) {
+ bidResponse.meta.advertiserDomains = adUnit.adomain;
+ }
- if (!isArray(serverResponse)) {
- return parseRTBResponse(serverResponse, adapterRequest);
+ bidResponses.push(bidResponse);
+ });
}
- serverResponse.forEach(serverBidResponse => {
- bids = flatten(bids, parseRTBResponse(serverBidResponse, adapterRequest));
- });
-
- return bids;
+ return bidResponses;
},
+ getUserSyncs: function (syncOptions, serverResponses) {
+ const syncs = [];
+ for (const response of serverResponses) {
+ if (syncOptions.iframeEnabled && response.body.params.userSyncURL) {
+ syncs.push({
+ type: 'iframe',
+ url: response.body.params.userSyncURL
+ });
+ }
+ if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) {
+ const pixels = response.body.params.userSyncPixels.map(pixel => {
+ return {
+ type: 'image',
+ url: pixel
+ }
+ })
+ syncs.push(...pixels)
+ }
+ }
+ return syncs;
+ },
+ onBidWon: function (bid) {
+ if (bid == null) {
+ return;
+ }
- transformBidParams(params) {
- return convertTypes({
- 'aid': 'number',
- }, params);
+ logInfo('onBidWon:', bid);
+ if (bid.hasOwnProperty('nurl') && bid.nurl.length > 0) {
+ triggerPixel(bid.nurl);
+ }
}
};
-function parseRTBResponse(serverResponse, adapterRequest) {
- const isEmptyResponse = !serverResponse || !isArray(serverResponse.bids);
- const bids = [];
+registerBidder(spec);
- if (isEmptyResponse) {
- return bids;
+/**
+ * Get floor price
+ * @param bid {bid}
+ * @returns {Number}
+ */
+function getFloor(bid, mediaType, currency) {
+ if (!isFn(bid.getFloor)) {
+ return 0;
}
+ let floorResult = bid.getFloor({
+ currency: currency,
+ mediaType: mediaType,
+ size: '*'
+ });
+ return floorResult.currency === currency && floorResult.floor ? floorResult.floor : 0;
+}
- serverResponse.bids.forEach(serverBid => {
- const request = find(adapterRequest.bids, (bidRequest) => {
- return bidRequest.bidId === serverBid.requestId;
- });
+/**
+ * Get the the ad sizes array from the bid
+ * @param bid {bid}
+ * @returns {Array}
+ */
+function getSizesArray(bid, mediaType) {
+ let sizesArray = []
- if (serverBid.cpm !== 0 && request !== undefined) {
- const bid = createBid(serverBid, request);
+ if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) {
+ sizesArray = bid.mediaTypes[mediaType].sizes;
+ } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) {
+ sizesArray = bid.sizes;
+ }
- bids.push(bid);
- }
+ return sizesArray;
+}
+
+/**
+ * Get schain string value
+ * @param schainObject {Object}
+ * @returns {string}
+ */
+function getSupplyChain(schainObject) {
+ if (isEmpty(schainObject)) {
+ return '';
+ }
+ let scStr = `${schainObject.ver},${schainObject.complete}`;
+ schainObject.nodes.forEach((node) => {
+ scStr += '!';
+ scStr += `${getEncodedValIfNotEmpty(node.asi)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.sid)},`;
+ scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`;
+ scStr += `${getEncodedValIfNotEmpty(node.rid)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.name)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.domain)}`;
});
+ return scStr;
+}
- return bids;
+/**
+ * Get encoded node value
+ * @param val {string}
+ * @returns {string}
+ */
+function getEncodedValIfNotEmpty(val) {
+ return !isEmpty(val) ? encodeURIComponent(val) : '';
}
-function bidToTag(bidRequests, adapterRequest) {
- // start publisher env
- const tag = {
- // TODO: is 'page' the right value here?
- Domain: deepAccess(adapterRequest, 'refererInfo.page')
- };
- if (config.getConfig('coppa') === true) {
- tag.Coppa = 1;
+/**
+ * Get preferred user-sync method based on publisher configuration
+ * @param bidderCode {string}
+ * @returns {string}
+ */
+function getAllowedSyncMethod(filterSettings, bidderCode) {
+ const iframeConfigsToCheck = ['all', 'iframe'];
+ const pixelConfigToCheck = 'image';
+ if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) {
+ return SUPPORTED_SYNC_METHODS.IFRAME;
}
- if (deepAccess(adapterRequest, 'gdprConsent.gdprApplies')) {
- tag.GDPR = 1;
- tag.GDPRConsent = deepAccess(adapterRequest, 'gdprConsent.consentString');
+ if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) {
+ return SUPPORTED_SYNC_METHODS.PIXEL;
}
- if (deepAccess(adapterRequest, 'uspConsent')) {
- tag.USP = deepAccess(adapterRequest, 'uspConsent');
+}
+
+/**
+ * Check if sync rule is supported
+ * @param syncRule {Object}
+ * @param bidderCode {string}
+ * @returns {boolean}
+ */
+function isSyncMethodAllowed(syncRule, bidderCode) {
+ if (!syncRule) {
+ return false;
}
- if (deepAccess(bidRequests[0], 'schain')) {
- tag.Schain = deepAccess(bidRequests[0], 'schain');
+ const isInclude = syncRule.filter === 'include';
+ const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode];
+ return isInclude && contains(bidders, bidderCode);
+}
+
+/**
+ * Get the seller endpoint
+ * @param testMode {boolean}
+ * @returns {string}
+ */
+function getEndpoint(testMode) {
+ return testMode
+ ? SELLER_ENDPOINT + MODES.TEST
+ : SELLER_ENDPOINT + MODES.PRODUCTION;
+}
+
+/**
+ * get device type
+ * @param uad {ua}
+ * @returns {string}
+ */
+function getDeviceType(ua) {
+ if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i
+ .test(ua.toLowerCase())) {
+ return '5';
}
- if (deepAccess(bidRequests[0], 'userId')) {
- tag.UserIds = deepAccess(bidRequests[0], 'userId');
+ if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i
+ .test(ua.toLowerCase())) {
+ return '4';
}
- if (deepAccess(bidRequests[0], 'userIdAsEids')) {
- tag.UserEids = deepAccess(bidRequests[0], 'userIdAsEids');
+ if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i
+ .test(ua.toLowerCase())) {
+ return '3';
}
- // end publisher env
- const bids = [];
+ return '1';
+}
+
+function generateBidsParams(validBidRequests, bidderRequest) {
+ const bidsArray = [];
- for (let i = 0, length = bidRequests.length; i < length; i++) {
- const bid = prepareBidRequests(bidRequests[i]);
- bids.push(bid);
+ if (validBidRequests.length) {
+ validBidRequests.forEach(bid => {
+ bidsArray.push(generateBidParameters(bid, bidderRequest));
+ });
}
- return { tag, bids };
+ return bidsArray;
}
/**
- * Parse mediaType
- * @param bidReq {object}
- * @returns {object}
+ * Generate bid specific parameters
+ * @param {bid} bid
+ * @param {bidderRequest} bidderRequest
+ * @returns {Object} bid specific params object
*/
-function prepareBidRequests(bidReq) {
- const mediaType = deepAccess(bidReq, 'mediaTypes.video') ? VIDEO : DISPLAY;
- const sizes = mediaType === VIDEO ? deepAccess(bidReq, 'mediaTypes.video.playerSize') : deepAccess(bidReq, 'mediaTypes.banner.sizes');
- const bidReqParams = {
- 'CallbackId': bidReq.bidId,
- 'Aid': bidReq.params.aid,
- 'AdType': mediaType,
- 'Sizes': parseSizesInput(sizes).join(',')
+function generateBidParameters(bid, bidderRequest) {
+ const {params} = bid;
+ const mediaType = isBanner(bid) ? BANNER : VIDEO;
+ const sizesArray = getSizesArray(bid, mediaType);
+ const currency = params.currency || config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY;
+
+ // fix floor price in case of NAN
+ if (isNaN(params.floorPrice)) {
+ params.floorPrice = 0;
+ }
+
+ const bidObject = {
+ mediaType,
+ adUnitCode: getBidIdParameter('adUnitCode', bid),
+ sizes: sizesArray,
+ currency: currency,
+ floorPrice: Math.max(getFloor(bid, mediaType, currency), params.floorPrice),
+ bidId: getBidIdParameter('bidId', bid),
+ loop: getBidIdParameter('bidderRequestsCount', bid),
+ bidderRequestId: getBidIdParameter('bidderRequestId', bid),
+ transactionId: bid.ortb2Imp?.ext?.tid || '',
+ coppa: 0,
};
- bidReqParams.PlacementId = bidReq.adUnitCode;
- if (bidReq.params.iframe) {
- bidReqParams.AdmType = 'iframe';
+ const pos = deepAccess(bid, `mediaTypes.${mediaType}.pos`);
+ if (pos) {
+ bidObject.pos = pos;
+ }
+
+ const gpid = deepAccess(bid, `ortb2Imp.ext.gpid`);
+ if (gpid) {
+ bidObject.gpid = gpid;
}
+
+ const placementId = params.placementId || deepAccess(bid, `mediaTypes.${mediaType}.name`);
+ if (placementId) {
+ bidObject.placementId = placementId;
+ }
+
+ const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`);
+ if (mimes) {
+ bidObject.mimes = mimes;
+ }
+ const api = deepAccess(bid, `mediaTypes.${mediaType}.api`);
+ if (api) {
+ bidObject.api = api;
+ }
+
+ const sua = deepAccess(bid, `ortb2.device.sua`);
+ if (sua) {
+ bidObject.sua = sua;
+ }
+
+ const coppa = deepAccess(bid, `ortb2.regs.coppa`);
+ if (coppa) {
+ bidObject.coppa = 1;
+ }
+
if (mediaType === VIDEO) {
- const context = deepAccess(bidReq, 'mediaTypes.video.context');
- if (context === ADPOD) {
- bidReqParams.Adpod = deepAccess(bidReq, 'mediaTypes.video');
+ const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`);
+ let playbackMethodValue;
+
+ // verify playbackMethod is of type integer array, or integer only.
+ if (Array.isArray(playbackMethod) && isInteger(playbackMethod[0])) {
+ // only the first playbackMethod in the array will be used, according to OpenRTB 2.5 recommendation
+ playbackMethodValue = playbackMethod[0];
+ } else if (isInteger(playbackMethod)) {
+ playbackMethodValue = playbackMethod;
+ }
+
+ if (playbackMethodValue) {
+ bidObject.playbackMethod = playbackMethodValue;
+ }
+
+ const placement = deepAccess(bid, `mediaTypes.video.placement`);
+ if (placement) {
+ bidObject.placement = placement;
+ }
+
+ const minDuration = deepAccess(bid, `mediaTypes.video.minduration`);
+ if (minDuration) {
+ bidObject.minDuration = minDuration;
+ }
+
+ const maxDuration = deepAccess(bid, `mediaTypes.video.maxduration`);
+ if (maxDuration) {
+ bidObject.maxDuration = maxDuration;
+ }
+
+ const skip = deepAccess(bid, `mediaTypes.video.skip`);
+ if (skip) {
+ bidObject.skip = skip;
+ }
+
+ const linearity = deepAccess(bid, `mediaTypes.video.linearity`);
+ if (linearity) {
+ bidObject.linearity = linearity;
+ }
+
+ const protocols = deepAccess(bid, `mediaTypes.video.protocols`);
+ if (protocols) {
+ bidObject.protocols = protocols;
+ }
+
+ const plcmt = deepAccess(bid, `mediaTypes.video.plcmt`);
+ if (plcmt) {
+ bidObject.plcmt = plcmt;
}
}
- return bidReqParams;
+
+ return bidObject;
}
-/**
- * Prepare all parameters for request
- * @param bidderRequest {object}
- * @returns {object}
- */
-function getMediaType(bidderRequest) {
- return deepAccess(bidderRequest, 'mediaTypes.video') ? VIDEO : BANNER;
+function isBanner(bid) {
+ return bid.mediaTypes && bid.mediaTypes.banner;
}
/**
- * Configure new bid by response
- * @param bidResponse {object}
- * @param bidRequest {Object}
- * @returns {object}
+ * Generate params that are common between all bids
+ * @param {single bid object} generalObject
+ * @param {bidderRequest} bidderRequest
+ * @returns {object} the common params object
*/
-function createBid(bidResponse, bidRequest) {
- const mediaType = getMediaType(bidRequest)
- const context = deepAccess(bidRequest, 'mediaTypes.video.context');
- const bid = {
- requestId: bidResponse.requestId,
- creativeId: bidResponse.cmpId,
- height: bidResponse.height,
- currency: bidResponse.cur,
- width: bidResponse.width,
- cpm: bidResponse.cpm,
- netRevenue: true,
- mediaType,
- ttl: 300,
- meta: {
- advertiserDomains: bidResponse.adomain || []
+function generateGeneralParams(generalObject, bidderRequest) {
+ const domain = deepAccess(bidderRequest, 'refererInfo.domain') || window.location.hostname;
+ const {syncEnabled, filterSettings} = config.getConfig('userSync') || {};
+ const {bidderCode, timeout} = bidderRequest;
+ const generalBidParams = generalObject.params;
+
+ // these params are snake_case instead of camelCase to allow backwards compatability on the server.
+ // in the future, these will be converted to camelCase to match our convention.
+ const generalParams = {
+ wrapper_type: 'prebidjs',
+ wrapper_vendor: '$$PREBID_GLOBAL$$',
+ wrapper_version: '$prebid.version$',
+ adapter_version: ADAPTER_VERSION,
+ publisher_id: generalBidParams.org,
+ publisher_name: domain,
+ site_domain: domain,
+ dnt: getDNT() ? 1 : 0,
+ device_type: getDeviceType(navigator.userAgent),
+ ua: navigator.userAgent,
+ is_wrapper: !!generalBidParams.isWrapper,
+ session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject),
+ tmax: timeout
+ }
+
+ const userIdsParam = getBidIdParameter('userId', generalObject);
+ if (userIdsParam) {
+ generalParams.userIds = JSON.stringify(userIdsParam);
+ }
+
+ const ortb2Metadata = bidderRequest.ortb2 || {};
+ if (ortb2Metadata.site) {
+ generalParams.site_metadata = JSON.stringify(ortb2Metadata.site);
+ }
+ if (ortb2Metadata.user) {
+ generalParams.user_metadata = JSON.stringify(ortb2Metadata.user);
+ }
+
+ if (syncEnabled) {
+ const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode);
+ if (allowedSyncMethod) {
+ generalParams.cs_method = allowedSyncMethod;
}
- };
+ }
- if (mediaType === BANNER) {
- return Object.assign(bid, {
- ad: bidResponse.ad,
- adUrl: bidResponse.adUrl,
- });
+ if (bidderRequest.auctionStart) {
+ generalParams.auction_start = bidderRequest.auctionStart;
}
- if (context === ADPOD) {
- Object.assign(bid, {
- meta: {
- primaryCatId: bidResponse.primaryCatId,
- },
- video: {
- context: ADPOD,
- durationSeconds: bidResponse.durationSeconds
- }
- });
+
+ if (bidderRequest.uspConsent) {
+ generalParams.us_privacy = bidderRequest.uspConsent;
}
- Object.assign(bid, {
- vastUrl: bidResponse.vastUrl
- });
+ if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
+ generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies;
+ generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString;
+ }
- return bid;
-}
+ if (bidderRequest.gppConsent) {
+ generalParams.gpp = bidderRequest.gppConsent.gppString;
+ generalParams.gpp_sid = bidderRequest.gppConsent.applicableSections;
+ } else if (bidderRequest.ortb2?.regs?.gpp) {
+ generalParams.gpp = bidderRequest.ortb2.regs.gpp;
+ generalParams.gpp_sid = bidderRequest.ortb2.regs.gpp_sid;
+ }
-registerBidder(spec);
+ if (generalBidParams.ifa) {
+ generalParams.ifa = generalBidParams.ifa;
+ }
+
+ if (generalObject.schain) {
+ generalParams.schain = getSupplyChain(generalObject.schain);
+ }
+
+ if (bidderRequest && bidderRequest.refererInfo) {
+ generalParams.referrer = deepAccess(bidderRequest, 'refererInfo.ref');
+ generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href');
+ }
+
+ return generalParams;
+}
diff --git a/modules/openwebBidAdapter.md b/modules/openwebBidAdapter.md
index dc8bfa6c59e..36c1f0ca6c5 100644
--- a/modules/openwebBidAdapter.md
+++ b/modules/openwebBidAdapter.md
@@ -1,27 +1,53 @@
# Overview
-**Module Name**: OpenWeb Bidder Adapter
-**Module Type**: Bidder Adapter
-**Maintainer**: monetization@openweb.com
+Module Name: OpenWeb Bidder Adapter
+
+Module Type: Bidder Adapter
+
+Maintainer: monetization@openweb.com
+
# Description
-OpenWeb.com official prebid adapter. Available in both client and server side versions.
-OpenWeb header bidding adapter provides solution for accessing both Video and Display demand.
+Module that connects to OpenWeb's demand sources.
+
+The OpenWeb adapter requires setup and approval from OpenWeb. Please reach out to monetization@openweb.com to create an OpenWeb account.
+
+The adapter supports Video and Display demand.
+
+# Bid Parameters
+## Video
+
+| Name | Scope | Type | Description | Example
+| ---- | ----- | ---- | ----------- | -------
+| `org` | required | String | OpenWeb publisher Id provided by your OpenWeb representative | "1234567890abcdef12345678"
+| `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00
+| `placementId` | optional | String | A unique placement identifier | "12345678"
+| `testMode` | optional | Boolean | This activates the test mode | false
+| `currency` | optional | String | 3 letters currency | "EUR"
+
# Test Parameters
-```
- var adUnits = [
- // Banner adUnit
- {
- code: 'div-test-div',
- sizes: [[300, 250]],
+```javascript
+var adUnits = [
+ {
+ code: 'dfp-video-div',
+ sizes: [[640, 480]],
+ mediaTypes: {
+ video: {
+ playerSize: [[640, 480]],
+ context: 'instream'
+ }
+ },
bids: [{
bidder: 'openweb',
params: {
- aid: 529814
+ org: '1234567890abcdef12345678', // Required
+ floorPrice: 2.00, // Optional
+ placementId: '12345678', // Optional
+ testMode: false, // Optional,
}
}]
}
- ];
-```
+ ];
+```
\ No newline at end of file
diff --git a/test/spec/modules/openwebBidAdapter_spec.js b/test/spec/modules/openwebBidAdapter_spec.js
index c515c21690a..5a0264f00b8 100644
--- a/test/spec/modules/openwebBidAdapter_spec.js
+++ b/test/spec/modules/openwebBidAdapter_spec.js
@@ -2,386 +2,624 @@ import { expect } from 'chai';
import { spec } from 'modules/openwebBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import { config } from 'src/config.js';
+import { BANNER, VIDEO } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
-const DEFAULT_ADATPER_REQ = { bidderCode: 'openweb' };
-const DISPLAY_REQUEST = {
- 'bidder': 'openweb',
- 'params': {
- 'aid': 12345
- },
- 'schain': { ver: 1 },
- 'userId': { criteo: 2 },
- 'mediaTypes': { 'banner': { 'sizes': [300, 250] } },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '84ab500420319d',
-};
-
-const VIDEO_REQUEST = {
- 'bidder': 'openweb',
- 'mediaTypes': {
- 'video': {
- 'playerSize': [[480, 360], [640, 480]]
- }
- },
- 'params': {
- 'aid': 12345
- },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '84ab500420319d'
-};
-
-const ADPOD_REQUEST = {
- 'bidder': 'openweb',
- 'mediaTypes': {
- 'video': {
- 'context': 'adpod',
- 'playerSize': [[640, 480]],
- 'anyField': 10
- }
- },
- 'params': {
- 'aid': 12345
- },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '2e41f65424c87c'
-};
-
-const SERVER_VIDEO_RESPONSE = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'vastUrl': 'vastUrl',
- 'requestId': '2e41f65424c87c',
- 'url': '44F2AEB9BFC881B3',
- 'creative_id': 342516,
- 'durationSeconds': 30,
- 'cmpId': 342516,
- 'height': 480,
- 'cur': 'USD',
- 'width': 640,
- 'cpm': 0.9,
- 'adomain': ['a.com']
- }]
-};
-const SERVER_OUSTREAM_VIDEO_RESPONSE = SERVER_VIDEO_RESPONSE;
-const SERVER_DISPLAY_RESPONSE = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'ad': '',
- 'adUrl': 'adUrl',
- 'requestId': '2e41f65424c87c',
- 'creative_id': 342516,
- 'cmpId': 342516,
- 'height': 250,
- 'cur': 'USD',
- 'width': 300,
- 'cpm': 0.9
- }],
- 'cookieURLs': ['link1', 'link2']
-};
-const SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'ad': '',
- 'requestId': '2e41f65424c87c',
- 'creative_id': 342516,
- 'cmpId': 342516,
- 'height': 250,
- 'cur': 'USD',
- 'width': 300,
- 'cpm': 0.9
- }],
- 'cookieURLs': ['link3', 'link4'],
- 'cookieURLSTypes': ['image', 'iframe']
-};
-
-const videoBidderRequest = {
- bidderCode: 'bidderCode',
- bids: [{ mediaTypes: { video: {} }, bidId: '2e41f65424c87c' }]
-};
-
-const displayBidderRequest = {
- bidderCode: 'bidderCode',
- bids: [{ bidId: '2e41f65424c87c' }]
-};
-
-const displayBidderRequestWithConsents = {
- bidderCode: 'bidderCode',
- bids: [{ bidId: '2e41f65424c87c' }],
- gdprConsent: {
- gdprApplies: true,
- consentString: 'test'
- },
- uspConsent: 'iHaveIt'
-};
-
-const videoEqResponse = [{
- vastUrl: 'vastUrl',
- requestId: '2e41f65424c87c',
- creativeId: 342516,
- mediaType: 'video',
- netRevenue: true,
- currency: 'USD',
- height: 480,
- width: 640,
- ttl: 300,
- cpm: 0.9,
- meta: {
- advertiserDomains: ['a.com']
- }
-}];
-
-const displayEqResponse = [{
- requestId: '2e41f65424c87c',
- creativeId: 342516,
- mediaType: 'banner',
- netRevenue: true,
- currency: 'USD',
- ad: '',
- adUrl: 'adUrl',
- height: 250,
- width: 300,
- ttl: 300,
- cpm: 0.9,
- meta: {
- advertiserDomains: []
- }
-
-}];
-
-describe('openwebBidAdapter', () => {
+const ENDPOINT = 'https://hb.openwebmp.com/hb-multi';
+const TEST_ENDPOINT = 'https://hb.openwebmp.com/hb-multi-test';
+const TTL = 360;
+/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
+
+describe('openwebAdapter', function () {
const adapter = newBidder(spec);
- describe('inherited functions', () => {
- it('exists and is a function', () => {
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});
- describe('user syncs', () => {
- describe('as image', () => {
- it('should be returned if pixel enabled', () => {
- const syncs = spec.getUserSyncs({ pixelEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
-
- expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[0]]);
- expect(syncs.map(s => s.type)).to.deep.equal(['image']);
- })
- })
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
- describe('as iframe', () => {
- it('should be returned if iframe enabled', () => {
- const syncs = spec.getUserSyncs({ iframeEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'org': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
- expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[1]]);
- expect(syncs.map(s => s.type)).to.deep.equal(['iframe']);
- })
- })
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[640, 480]],
+ 'context': 'instream',
+ 'plcmt': 1
+ }
+ },
+ 'vastXml': '"..."'
+ },
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '""'
+ }
+ ];
+
+ const testModeBidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001',
+ 'testMode': true
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 2,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'openweb',
+ }
+ const placementId = '12345678';
+ const api = [1, 2];
+ const mimes = ['application/javascript', 'video/mp4', 'video/quicktime'];
+ const protocols = [2, 3, 5, 6];
+
+ it('sends the placementId to ENDPOINT via POST', function () {
+ bidRequests[0].params.placementId = placementId;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].placementId).to.equal(placementId);
+ });
- describe('user sync', () => {
- it('should not be returned if passed syncs where already used', () => {
- const syncs = spec.getUserSyncs({
- iframeEnabled: true,
- pixelEnabled: true
- }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('sends the plcmt to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].plcmt).to.equal(1);
+ });
- expect(syncs).to.deep.equal([]);
- })
+ it('sends the is_wrapper parameter to ENDPOINT via POST', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('is_wrapper');
+ expect(request.data.params.is_wrapper).to.equal(false);
+ });
- it('should not be returned if pixel not set', () => {
- const syncs = spec.getUserSyncs({}, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
- expect(syncs).to.be.empty;
- });
+ it('sends bid request to TEST ENDPOINT via POST', function () {
+ const request = spec.buildRequests(testModeBidRequests, bidderRequest);
+ expect(request.url).to.equal(TEST_ENDPOINT);
+ expect(request.method).to.equal('POST');
});
- describe('user syncs with both types', () => {
- it('should be returned if pixel and iframe enabled', () => {
- const mockedServerResponse = Object.assign({}, SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS, { 'cookieURLs': ['link5', 'link6'] });
- const syncs = spec.getUserSyncs({
- iframeEnabled: true,
- pixelEnabled: true
- }, [{ body: mockedServerResponse }]);
- expect(syncs.map(s => s.url)).to.deep.equal(mockedServerResponse.cookieURLs);
- expect(syncs.map(s => s.type)).to.deep.equal(mockedServerResponse.cookieURLSTypes);
- });
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
});
- });
- describe('isBidRequestValid', () => {
- it('should return true when required params found', () => {
- expect(spec.isBidRequestValid(VIDEO_REQUEST)).to.equal(true);
+ it('should send the correct supported api array', function () {
+ bidRequests[0].mediaTypes.video.api = api;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].api).to.be.an('array');
+ expect(request.data.bids[0].api).to.eql([1, 2]);
});
- it('should return false when required params are not passed', () => {
- let bid = Object.assign({}, VIDEO_REQUEST);
- delete bid.params;
- expect(spec.isBidRequestValid(bid)).to.equal(false);
+ it('should send the correct mimes array', function () {
+ bidRequests[1].mediaTypes.banner.mimes = mimes;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[1].mimes).to.be.an('array');
+ expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']);
});
- });
- describe('buildRequests', () => {
- let videoBidRequests = [VIDEO_REQUEST];
- let displayBidRequests = [DISPLAY_REQUEST];
- let videoAndDisplayBidRequests = [DISPLAY_REQUEST, VIDEO_REQUEST];
- const displayRequest = spec.buildRequests(displayBidRequests, DEFAULT_ADATPER_REQ);
- const videoRequest = spec.buildRequests(videoBidRequests, DEFAULT_ADATPER_REQ);
- const videoAndDisplayRequests = spec.buildRequests(videoAndDisplayBidRequests, DEFAULT_ADATPER_REQ);
-
- it('building requests as arrays', () => {
- expect(videoRequest).to.be.a('array');
- expect(displayRequest).to.be.a('array');
- expect(videoAndDisplayRequests).to.be.a('array');
- })
+ it('should send the correct protocols array', function () {
+ bidRequests[0].mediaTypes.video.protocols = protocols;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].protocols).to.be.an('array');
+ expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]);
+ });
- it('sending as POST', () => {
- const postActionMethod = 'POST'
- const comparator = br => br.method === postActionMethod;
- expect(videoRequest.every(comparator)).to.be.true;
- expect(displayRequest.every(comparator)).to.be.true;
- expect(videoAndDisplayRequests.every(comparator)).to.be.true;
- });
- it('forms correct ADPOD request', () => {
- const pbBidReqData = spec.buildRequests([ADPOD_REQUEST], DEFAULT_ADATPER_REQ)[0].data;
- const impRequest = pbBidReqData.BidRequests[0]
- expect(impRequest.AdType).to.be.equal('video');
- expect(impRequest.Adpod).to.be.a('object');
- expect(impRequest.Adpod.anyField).to.be.equal(10);
- })
- it('sends correct video bid parameters', () => {
- const data = videoRequest[0].data;
-
- const eq = {
- CallbackId: '84ab500420319d',
- AdType: 'video',
- Aid: 12345,
- Sizes: '480x360,640x480',
- PlacementId: 'adunit-code'
- };
- expect(data.BidRequests[0]).to.deep.equal(eq);
+ it('should send the correct sizes array', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sizes).to.be.an('array');
+ expect(request.data.bids[0].sizes).to.equal(bidRequests[0].sizes)
+ expect(request.data.bids[1].sizes).to.be.an('array');
+ expect(request.data.bids[1].sizes).to.equal(bidRequests[1].sizes)
});
- it('sends correct display bid parameters', () => {
- const data = displayRequest[0].data;
+ it('should send the correct media type', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].mediaType).to.equal(VIDEO)
+ expect(request.data.bids[1].mediaType).to.equal(BANNER)
+ });
- const eq = {
- CallbackId: '84ab500420319d',
- AdType: 'display',
- Aid: 12345,
- Sizes: '300x250',
- PlacementId: 'adunit-code'
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
};
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
- expect(data.BidRequests[0]).to.deep.equal(eq);
- });
-
- it('sends correct video and display bid parameters', () => {
- const bidRequests = videoAndDisplayRequests[0].data;
- const expectedBidReqs = [{
- CallbackId: '84ab500420319d',
- AdType: 'display',
- Aid: 12345,
- Sizes: '300x250',
- PlacementId: 'adunit-code'
- }, {
- CallbackId: '84ab500420319d',
- AdType: 'video',
- Aid: 12345,
- Sizes: '480x360,640x480',
- PlacementId: 'adunit-code'
- }]
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
- expect(bidRequests.BidRequests).to.deep.equal(expectedBidReqs);
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
});
- describe('publisher environment', () => {
- const sandbox = sinon.sandbox.create();
- sandbox.stub(config, 'getConfig').callsFake((key) => {
- const config = {
- 'coppa': true
- };
- return config[key];
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
});
- const bidRequestWithPubSettingsData = spec.buildRequests([DISPLAY_REQUEST], displayBidderRequestWithConsents)[0].data;
- sandbox.restore();
- it('sets GDPR', () => {
- expect(bidRequestWithPubSettingsData.GDPR).to.be.equal(1);
- expect(bidRequestWithPubSettingsData.GDPRConsent).to.be.equal(displayBidderRequestWithConsents.gdprConsent.consentString);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
});
- it('sets USP', () => {
- expect(bidRequestWithPubSettingsData.USP).to.be.equal(displayBidderRequestWithConsents.uspConsent);
- })
- it('sets Coppa', () => {
- expect(bidRequestWithPubSettingsData.Coppa).to.be.equal(1);
- })
- it('sets Schain', () => {
- expect(bidRequestWithPubSettingsData.Schain).to.be.deep.equal(DISPLAY_REQUEST.schain);
- })
- it('sets UserId\'s', () => {
- expect(bidRequestWithPubSettingsData.UserIds).to.be.deep.equal(DISPLAY_REQUEST.userId);
- })
- })
- });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
- describe('interpretResponse', () => {
- let serverResponse;
- let adapterRequest;
- let eqResponse;
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
- afterEach(() => {
- serverResponse = null;
- adapterRequest = null;
- eqResponse = null;
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
});
- it('should get correct video bid response', () => {
- serverResponse = SERVER_VIDEO_RESPONSE;
- adapterRequest = videoBidderRequest;
- eqResponse = videoEqResponse;
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
- bidServerResponseCheck();
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
});
- it('should get correct display bid response', () => {
- serverResponse = SERVER_DISPLAY_RESPONSE;
- adapterRequest = displayBidderRequest;
- eqResponse = displayEqResponse;
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
- bidServerResponseCheck();
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
});
- function bidServerResponseCheck() {
- const result = spec.interpretResponse({ body: serverResponse }, { adapterRequest });
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'test-consent-string', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'test-consent-string');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
- expect(result).to.deep.equal(eqResponse);
- }
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
- function nobidServerResponseCheck() {
- const noBidServerResponse = { bids: [] };
- const noBidResult = spec.interpretResponse({ body: noBidServerResponse }, { adapterRequest });
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
- expect(noBidResult.length).to.equal(0);
- }
+ it('should check sua param in bid request', function() {
+ const sua = {
+ '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': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ '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': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [{
+ cpm: 12.5,
+ vastXml: '',
+ width: 640,
+ height: 480,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: VIDEO
+ },
+ {
+ cpm: 12.5,
+ ad: '""',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER
+ }]
+ };
+
+ const expectedVideoResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: VIDEO,
+ meta: {
+ mediaType: VIDEO,
+ advertiserDomains: ['abc.com']
+ },
+ vastXml: '',
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ advertiserDomains: ['abc.com']
+ },
+ ad: '""'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedVideoResponse));
+ expect(Object.keys(result[1])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+
+ it('video type should have vastXml key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[0].vastXml).to.equal(expectedVideoResponse.vastXml)
+ });
+
+ it('banner type should have ad key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[1].ad).to.equal(expectedBannerResponse.ad)
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
- it('handles video nobid responses', () => {
- adapterRequest = videoBidderRequest;
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
- nobidServerResponseCheck();
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
});
- it('handles display nobid responses', () => {
- adapterRequest = displayBidderRequest;
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
- nobidServerResponseCheck();
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
});
+ })
- it('forms correct ADPOD response', () => {
- const videoBids = spec.interpretResponse({ body: SERVER_VIDEO_RESPONSE }, { adapterRequest: { bids: [ADPOD_REQUEST] } });
- expect(videoBids[0].video.durationSeconds).to.be.equal(30);
- expect(videoBids[0].video.context).to.be.equal('adpod');
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
})
- });
+ })
});