diff --git a/gulpfile.js b/gulpfile.js
index ced29b266a7..03a0a4a7559 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -76,7 +76,10 @@ function escapePostbidConfig() {
};
escapePostbidConfig.displayName = 'escape-postbid-config';
-function lint() {
+function lint(done) {
+ if (argv.nolint) {
+ return done();
+ }
return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'])
.pipe(eslint())
.pipe(eslint.format('stylish'))
diff --git a/integrationExamples/gpt/hello_world_adikteev.html b/integrationExamples/gpt/hello_world_adikteev.html
new file mode 100644
index 00000000000..7372ff12d7f
--- /dev/null
+++ b/integrationExamples/gpt/hello_world_adikteev.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+Basic Prebid.js Example
+Div-1
+
+
+
+
+
+
diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html
index 88d4839d984..6852b9f680a 100644
--- a/integrationExamples/gpt/pbjs_example_gpt.html
+++ b/integrationExamples/gpt/pbjs_example_gpt.html
@@ -312,8 +312,15 @@
width: '300',
height: '250',
}
- }
-
+ },
+ {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ currency: 'EUR',
+ bidFloorPrice: 0.1,
+ }
+ },
]
}, {
code: 'div-gpt-ad-12345678-1',
diff --git a/modules/adikteevBidAdapter.js b/modules/adikteevBidAdapter.js
new file mode 100644
index 00000000000..12d502de94a
--- /dev/null
+++ b/modules/adikteevBidAdapter.js
@@ -0,0 +1,94 @@
+import {registerBidder} from 'src/adapters/bidderFactory';
+import {BANNER} from 'src/mediaTypes';
+import * as utils from '../src/utils';
+import {config} from 'src/config';
+
+export const BIDDER_CODE = 'adikteev';
+export const ENDPOINT_URL = 'https://serve-adserver.adikteev.com/api/prebid/bid';
+export const ENDPOINT_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/bid';
+export const USER_SYNC_IFRAME_URL = 'https://serve-adserver.adikteev.com/api/prebid/sync-iframe';
+export const USER_SYNC_IFRAME_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/sync-iframe';
+export const USER_SYNC_IMAGE_URL = 'https://serve-adserver.adikteev.com/api/prebid/sync-image';
+export const USER_SYNC_IMAGE_URL_STAGING = 'https://serve-adserver-staging.adikteev.com/api/prebid/sync-image';
+
+export let stagingEnvironmentSwitch = false; // Don't use it. Allow us to make tests on staging
+
+export function setstagingEnvironmentSwitch(value) {
+ stagingEnvironmentSwitch = value;
+}
+
+function validateSizes(sizes) {
+ if (!utils.isArray(sizes) || typeof sizes[0] === 'undefined') {
+ return false;
+ }
+ return sizes.every(size => utils.isArray(size) && size.length === 2);
+}
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+
+ isBidRequestValid: (bid) => {
+ setstagingEnvironmentSwitch(stagingEnvironmentSwitch || !!bid.params.stagingEnvironment);
+ return !!(
+ bid &&
+ bid.params &&
+ bid.params.bidFloorPrice &&
+ bid.params.placementId &&
+ bid.bidder === BIDDER_CODE &&
+ validateSizes(bid.mediaTypes.banner.sizes)
+ );
+ },
+
+ buildRequests: (validBidRequests, bidderRequest) => {
+ const payload = {
+ validBidRequests,
+ bidderRequest,
+ refererInfo: bidderRequest.refererInfo,
+ currency: config.getConfig('currency'),
+ userAgent: navigator.userAgent,
+ screen: {
+ width: window.screen.width,
+ height: window.screen.height
+ },
+ language: navigator.language,
+ cookies: document.cookie.split(';'),
+ prebidUpdateVersion: '1.29.0',
+ };
+ return {
+ method: 'POST',
+ url: stagingEnvironmentSwitch ? ENDPOINT_URL_STAGING : ENDPOINT_URL,
+ data: JSON.stringify(payload),
+ };
+ },
+
+ interpretResponse: (serverResponse, bidRequests) => {
+ const returnedBids = [];
+ const validBidRequests = JSON.parse(bidRequests.data).validBidRequests;
+ serverResponse.body.forEach((value, index) => {
+ const overrides = {
+ requestId: validBidRequests[index].bidId,
+ };
+ returnedBids.push(Object.assign({}, value, overrides));
+ });
+ return returnedBids;
+ },
+
+ getUserSyncs: (syncOptions, serverResponses) => {
+ const syncs = [];
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: stagingEnvironmentSwitch ? USER_SYNC_IFRAME_URL_STAGING : USER_SYNC_IFRAME_URL,
+ });
+ }
+ if (syncOptions.pixelEnabled && serverResponses.length > 0) {
+ syncs.push({
+ type: 'image',
+ url: stagingEnvironmentSwitch ? USER_SYNC_IMAGE_URL_STAGING : USER_SYNC_IMAGE_URL,
+ });
+ }
+ return syncs;
+ },
+};
+registerBidder(spec);
diff --git a/modules/adikteevBidAdapter.md b/modules/adikteevBidAdapter.md
new file mode 100644
index 00000000000..d5008f61b03
--- /dev/null
+++ b/modules/adikteevBidAdapter.md
@@ -0,0 +1,35 @@
+# Overview
+
+```
+Module Name: Adikteev Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: adnetwork@adikteev.com
+```
+
+# Description
+
+Module that connects to Adikteev's demand sources
+
+# Test Parameters
+
+``` javascript
+ var adUnits = [
+ {
+ code: 'test-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]], // a display size
+ }
+ },
+ bids: [
+ {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ }
+ }
+ ]
+ }
+ ];
+```
diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js
index aaec207dc1e..19aa5e7cf73 100644
--- a/modules/appnexusBidAdapter.js
+++ b/modules/appnexusBidAdapter.js
@@ -233,7 +233,9 @@ function newBid(serverBid, rtbBid, bidderRequest) {
netRevenue: true,
ttl: 300,
appnexus: {
- buyerMemberId: rtbBid.buyer_member_id
+ buyerMemberId: rtbBid.buyer_member_id,
+ dealPriority: rtbBid.deal_priority,
+ dealCode: rtbBid.deal_code
}
};
diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js
new file mode 100644
index 00000000000..042251ea035
--- /dev/null
+++ b/modules/emx_digitalBidAdapter.js
@@ -0,0 +1,124 @@
+import * as utils from 'src/utils';
+import {
+ registerBidder
+} from 'src/adapters/bidderFactory';
+import {
+ BANNER
+} from 'src/mediaTypes';
+import {
+ config
+} from 'src/config';
+
+const BIDDER_CODE = 'emx_digital';
+const ENDPOINT = 'hb.emxdgt.com';
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+ isBidRequestValid: function (bid) {
+ return !!(bid.params.tagid);
+ },
+ buildRequests: function (validBidRequests, bidRequests) {
+ const {host, href, protocol} = utils.getTopWindowLocation();
+ let emxData = {};
+ let emxImps = [];
+ const auctionId = bidRequests.auctionId;
+ const timeout = config.getConfig('bidderTimeout');
+ const timestamp = Date.now();
+ const url = location.protocol + '//' + ENDPOINT + ('?t=' + timeout + '&ts=' + timestamp);
+
+ utils._each(validBidRequests, function (bid) {
+ let tagId = String(utils.getBidIdParameter('tagid', bid.params));
+ let bidFloor = utils.getBidIdParameter('bidfloor', bid.params) || 0;
+ let emxBid = {
+ id: bid.bidId,
+ tid: bid.transactionId,
+ tagid: tagId,
+ secure: protocol === 'https:' ? 1 : 0,
+ banner: {
+ format: bid.sizes.map(function (size) {
+ return {
+ w: size[0],
+ h: size[1]
+ };
+ }),
+ w: bid.sizes[0][0],
+ h: bid.sizes[0][1]
+ }
+ }
+ if (bidFloor > 0) {
+ emxBid.bidfloor = bidFloor
+ }
+ emxImps.push(emxBid);
+ });
+ emxData = {
+ id: auctionId,
+ imp: emxImps,
+ site: {
+ domain: host,
+ page: href
+ }
+ };
+ if (bidRequests.gdprConsent) {
+ emxData.regs = {
+ ext: {
+ gdpr: bidRequests.gdprConsent.gdprApplies === true ? 1 : 0
+ }
+ };
+ }
+ if (bidRequests.gdprConsent && bidRequests.gdprConsent.gdprApplies) {
+ emxData.user = {
+ ext: {
+ consent: bidRequests.gdprConsent.consentString
+ }
+ };
+ }
+ return {
+ method: 'POST',
+ url: url,
+ data: JSON.stringify(emxData),
+ options: {
+ withCredentials: true
+ }
+ };
+ },
+ interpretResponse: function (serverResponse) {
+ let emxBidResponses = [];
+ let response = serverResponse.body || {};
+ if (response.seatbid && response.seatbid.length > 0 && response.seatbid[0].bid) {
+ response.seatbid.forEach(function (emxBid) {
+ emxBid = emxBid.bid[0];
+ emxBidResponses.push({
+ requestId: emxBid.id,
+ cpm: emxBid.price,
+ width: emxBid.w,
+ height: emxBid.h,
+ creativeId: emxBid.crid || emxBid.id,
+ dealId: emxBid.dealid || null,
+ currency: 'USD',
+ netRevenue: true,
+ mediaType: BANNER,
+ ad: decodeURIComponent(emxBid.adm),
+ ttl: emxBid.ttl
+ });
+ });
+ }
+ return emxBidResponses;
+ },
+ getUserSyncs: function (syncOptions) {
+ const syncs = [];
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: '//biddr.brealtime.com/check.html'
+ });
+ }
+ if (syncOptions.pixelEnabled) {
+ syncs.push({
+ type: 'image',
+ url: '//edba.brealtime.com/'
+ });
+ }
+ return syncs;
+ }
+};
+registerBidder(spec);
diff --git a/modules/emx_digitalBidAdapter.md b/modules/emx_digitalBidAdapter.md
new file mode 100644
index 00000000000..c9435e2f1d1
--- /dev/null
+++ b/modules/emx_digitalBidAdapter.md
@@ -0,0 +1,38 @@
+# Overview
+
+```
+Module Name: EMX Digital Adapter
+Module Type: Bidder Adapter
+Maintainer: git@emxdigital.com
+```
+
+# Description
+
+The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner media type only.
+
+Note: The EMX Digital adapter requires approval and implementation guidelines from the EMX team, including existing publishers that work with EMX Digital. Please reach out to your account manager or prebid@emxdigital.com for more information.
+
+The bidder code should be ```emx_digital```
+The params used by the bidder are :
+```tagid``` - string (mandatory)
+```bidfloor``` - string (optional)
+
+# Test Parameters
+```
+var adUnits = [{
+ code: 'banner-div',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250], [300, 600]
+ }
+ },
+ bids: [
+ {
+ bidder: 'emx_digital',
+ params: {
+ tagid: '25251',
+ }
+ }]
+}];
+```
diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js
new file mode 100644
index 00000000000..660b5c66a78
--- /dev/null
+++ b/modules/gridBidAdapter.js
@@ -0,0 +1,151 @@
+import * as utils from 'src/utils';
+import {registerBidder} from 'src/adapters/bidderFactory';
+const BIDDER_CODE = 'grid';
+const ENDPOINT_URL = '//grid.bidswitch.net/hb';
+const TIME_TO_LIVE = 360;
+const LOG_ERROR_MESS = {
+ noAuid: 'Bid from response has no auid parameter - ',
+ noAdm: 'Bid from response has no adm parameter - ',
+ noBid: 'Array of bid objects is empty',
+ noPlacementCode: 'Can\'t find in requested bids the bid with auid - ',
+ emptyUids: 'Uids should be not empty',
+ emptySeatbid: 'Seatbid array from response has empty item',
+ emptyResponse: 'Response is empty',
+ hasEmptySeatbidArray: 'Response has empty seatbid array',
+ hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - '
+};
+export const spec = {
+ code: BIDDER_CODE,
+ /**
+ * Determines whether or not the given bid request is valid.
+ *
+ * @param {BidRequest} bid The bid params to validate.
+ * @return boolean True if this is a valid bid, and false otherwise.
+ */
+ isBidRequestValid: function(bid) {
+ return !!bid.params.uid;
+ },
+ /**
+ * Make a server request from the list of BidRequests.
+ *
+ * @param {BidRequest[]} validBidRequests - an array of bids
+ * @param {bidderRequest} bidderRequest bidder request object
+ * @return ServerRequest Info describing the request to the server.
+ */
+ buildRequests: function(validBidRequests, bidderRequest) {
+ const auids = [];
+ const bidsMap = {};
+ const bids = validBidRequests || [];
+ let reqId;
+
+ bids.forEach(bid => {
+ reqId = bid.bidderRequestId;
+ if (!bidsMap[bid.params.uid]) {
+ bidsMap[bid.params.uid] = [bid];
+ auids.push(bid.params.uid);
+ } else {
+ bidsMap[bid.params.uid].push(bid);
+ }
+ });
+
+ const payload = {
+ u: utils.getTopWindowUrl(),
+ auids: auids.join(','),
+ r: reqId
+ };
+
+ if (bidderRequest) {
+ if (bidderRequest.timeout) {
+ payload.wtimeout = bidderRequest.timeout;
+ }
+ if (bidderRequest.gdprConsent) {
+ if (bidderRequest.gdprConsent.consentString) {
+ payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
+ }
+ payload.gdpr_applies =
+ (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean')
+ ? Number(bidderRequest.gdprConsent.gdprApplies) : 1;
+ }
+ }
+
+ return {
+ method: 'GET',
+ url: ENDPOINT_URL,
+ data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''),
+ bidsMap: bidsMap,
+ };
+ },
+ /**
+ * Unpack the response from the server into a list of bids.
+ *
+ * @param {*} serverResponse A successful response from the server.
+ * @param {*} bidRequest
+ * @return {Bid[]} An array of bids which were nested inside the server.
+ */
+ interpretResponse: function(serverResponse, bidRequest) {
+ serverResponse = serverResponse && serverResponse.body;
+ const bidResponses = [];
+ const bidsMap = bidRequest.bidsMap;
+
+ let errorMessage;
+
+ if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse;
+ else if (serverResponse.seatbid && !serverResponse.seatbid.length) {
+ errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray;
+ }
+
+ if (!errorMessage && serverResponse.seatbid) {
+ serverResponse.seatbid.forEach(respItem => {
+ _addBidResponse(_getBidFromResponse(respItem), bidsMap, bidResponses);
+ });
+ }
+ if (errorMessage) utils.logError(errorMessage);
+ return bidResponses;
+ }
+}
+
+function _getBidFromResponse(respItem) {
+ if (!respItem) {
+ utils.logError(LOG_ERROR_MESS.emptySeatbid);
+ } else if (!respItem.bid) {
+ utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem));
+ } else if (!respItem.bid[0]) {
+ utils.logError(LOG_ERROR_MESS.noBid);
+ }
+ return respItem && respItem.bid && respItem.bid[0];
+}
+
+function _addBidResponse(serverBid, bidsMap, bidResponses) {
+ if (!serverBid) return;
+ let errorMessage;
+ if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid);
+ if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid);
+ else {
+ const awaitingBids = bidsMap[serverBid.auid];
+ if (awaitingBids) {
+ awaitingBids.forEach(bid => {
+ const bidResponse = {
+ requestId: bid.bidId, // bid.bidderRequestId,
+ bidderCode: spec.code,
+ cpm: serverBid.price,
+ width: serverBid.w,
+ height: serverBid.h,
+ creativeId: serverBid.auid, // bid.bidId,
+ currency: 'USD',
+ netRevenue: false,
+ ttl: TIME_TO_LIVE,
+ ad: serverBid.adm,
+ dealId: serverBid.dealid
+ };
+ bidResponses.push(bidResponse);
+ });
+ } else {
+ errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid;
+ }
+ }
+ if (errorMessage) {
+ utils.logError(errorMessage);
+ }
+}
+
+registerBidder(spec);
diff --git a/modules/gridBidAdapter.md b/modules/gridBidAdapter.md
new file mode 100755
index 00000000000..9b7b0e0515e
--- /dev/null
+++ b/modules/gridBidAdapter.md
@@ -0,0 +1,40 @@
+# Overview
+
+Module Name: The Grid Media Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: grid-tech@themediagrid.com
+
+# Description
+
+Module that connects to Grid demand source to fetch bids.
+
+# Test Parameters
+```
+ var adUnits = [
+ {
+ code: 'test-div',
+ sizes: [[300, 250]],
+ bids: [
+ {
+ bidder: "grid",
+ params: {
+ uid: '1',
+ priceType: 'gross' // by default is 'net'
+ }
+ }
+ ]
+ },{
+ code: 'test-div',
+ sizes: [[728, 90]],
+ bids: [
+ {
+ bidder: "grid",
+ params: {
+ uid: 2,
+ priceType: 'gross'
+ }
+ }
+ ]
+ }
+ ];
+```
\ No newline at end of file
diff --git a/modules/inskinBidAdapter.js b/modules/inskinBidAdapter.js
index 0e7e28b9b6b..27d01e677ef 100644
--- a/modules/inskinBidAdapter.js
+++ b/modules/inskinBidAdapter.js
@@ -59,6 +59,7 @@ export const spec = {
if (bidderRequest && bidderRequest.gdprConsent) {
data.consent = {
+ gdprVendorId: 150,
gdprConsentString: bidderRequest.gdprConsent.consentString,
// will check if the gdprApplies field was populated with a boolean value (ie from page config). If it's undefined, then default to true
gdprConsentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
diff --git a/modules/justpremiumBidAdapter.js b/modules/justpremiumBidAdapter.js
index 48b6805c0e1..c31f485020e 100644
--- a/modules/justpremiumBidAdapter.js
+++ b/modules/justpremiumBidAdapter.js
@@ -122,6 +122,16 @@ export const spec = {
}
+export let pixel = {
+ fire(url) {
+ let img = document.createElement('img')
+ img.src = url
+ img.id = 'jp-pixel-track'
+ img.style.cssText = 'display:none !important;'
+ document.body.appendChild(img)
+ }
+};
+
function track (data, payload, type) {
let pubUrl = ''
@@ -147,11 +157,7 @@ ru=${encodeURIComponent(pubUrl)}&tt=&siw=&sh=${payload.sh}&sw=${payload.sw}&wh=$
sd=&_c=&et=&aid=&said=&ei=&fc=&sp=&at=bidder&cid=&ist=&mg=&dl=&dlt=&ev=&vt=&zid=${payload.id}&dr=${duration}&di=&pr=&
cw=&ch=&nt=&st=&jp=${encodeURIComponent(JSON.stringify(jp))}&ty=${type}`
- let img = document.createElement('img')
- img.src = pixelUrl
- img.id = 'jp-pixel-track'
- img.style.cssText = 'display:none !important;'
- document.body.appendChild(img)
+ pixel.fire(pixelUrl);
}
function findBid (params, bids) {
diff --git a/modules/oneVideoBidAdapter.js b/modules/oneVideoBidAdapter.js
index 5b1fd999ee6..bd341dfd79f 100644
--- a/modules/oneVideoBidAdapter.js
+++ b/modules/oneVideoBidAdapter.js
@@ -136,7 +136,6 @@ function isConsentRequired(consentData) {
function getRequestData(bid, consentData) {
let loc = utils.getTopWindowLocation();
- let global = (window.top) ? window.top : window;
let page = (bid.params.site && bid.params.site.page) ? (bid.params.site.page) : (loc.href);
let ref = (bid.params.site && bid.params.site.referrer) ? bid.params.site.referrer : utils.getTopWindowReferrer();
let bidData = {
@@ -160,7 +159,7 @@ function getRequestData(bid, consentData) {
ref: ref
},
device: {
- ua: global.navigator.userAgent
+ ua: navigator.userAgent
},
tmax: 200
};
diff --git a/modules/openxoutstreamBidAdapter.js b/modules/openxoutstreamBidAdapter.js
index dde101f25d5..aee260e0a11 100644
--- a/modules/openxoutstreamBidAdapter.js
+++ b/modules/openxoutstreamBidAdapter.js
@@ -20,28 +20,21 @@ export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: SUPPORTED_AD_TYPES,
isBidRequestValid: function(bidRequest) {
- if (bidRequest.params.delDomain) {
- return !!bidRequest.params.unit || utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
- }
- return false;
+ return !!(bidRequest.params.delDomain && bidRequest.params.unit)
},
buildRequests: function(bidRequests, bidderRequest) {
if (bidRequests.length === 0) {
return [];
}
let requests = [];
- requests.push(buildOXBannerRequest(bidRequests, bidderRequest));
+ bidRequests.forEach(bid => {
+ requests.push(buildOXBannerRequest(bid, bidderRequest));
+ })
return requests;
},
- interpretResponse: function(serverResponse, serverRequest) {
- return handleVastResponse(serverResponse, serverRequest.payload)
+ interpretResponse: function(bid, serverResponse) {
+ return handleVastResponse(bid, serverResponse.payload)
},
-
- transformBidParams: function(params, isOpenRtb) {
- return utils.convertTypes({
- 'unit': 'string',
- }, params);
- }
};
function getViewportDimensions(isIfr) {
@@ -70,7 +63,7 @@ function getViewportDimensions(isIfr) {
return `${width}x${height}`;
}
-function buildCommonQueryParamsFromBids(bids, bidderRequest) {
+function buildCommonQueryParamsFromBids(bid, bidderRequest) {
const isInIframe = utils.inIframe();
let defaultParams;
defaultParams = {
@@ -82,13 +75,13 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
tz: new Date().getTimezoneOffset(),
tws: getViewportDimensions(isInIframe),
be: 1,
- bc: bids[0].params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
- auid: '540141567',
- dddid: utils._map(bids, bid => bid.transactionId).join(','),
+ bc: bid.params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
+ auid: bid.params.unit,
+ dddid: bid.transactionId,
openrtb: '%7B%22mimes%22%3A%5B%22video%2Fmp4%22%5D%7D',
nocache: new Date().getTime(),
- vht: bids[0].params.height || bids[0].sizes[0][1],
- vwd: bids[0].params.width || bids[0].sizes[0][0]
+ vht: bid.params.height || bid.sizes[0][1],
+ vwd: bid.params.width || bid.sizes[0][0]
};
if (utils.deepAccess(bidderRequest, 'gdprConsent')) {
@@ -110,24 +103,24 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
return defaultParams;
}
-function buildOXBannerRequest(bids, bidderRequest) {
- let queryParams = buildCommonQueryParamsFromBids(bids, bidderRequest);
- queryParams.aus = utils._map(bids, bid => utils.parseSizesInput(bid.sizes).join(',')).join('|');
+function buildOXBannerRequest(bid, bidderRequest) {
+ let queryParams = buildCommonQueryParamsFromBids(bid, bidderRequest);
+ queryParams.aus = utils.parseSizesInput(bid.sizes).join(',');
- if (bids.some(bid => bid.params.doNotTrack)) {
+ if (bid.params.doNotTrack) {
queryParams.ns = 1;
}
- if (bids.some(bid => bid.params.coppa)) {
+ if (bid.params.coppa) {
queryParams.tfcd = 1;
}
- let url = `https://${bids[0].params.delDomain}/v/1.0/avjp`
+ let url = `https://${bid.params.delDomain}/v/1.0/avjp`
return {
method: 'GET',
url: url,
data: queryParams,
- payload: {'bids': bids}
+ payload: {'bid': bid}
};
}
@@ -146,7 +139,7 @@ function handleVastResponse(response, serverResponse) {
const ymAdsScript = '';
let bidResponse = {};
- bidResponse.requestId = serverResponse.bids[0].bidId;
+ bidResponse.requestId = serverResponse.bid.bidId;
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.netRevenue = NET_REVENUE;
bidResponse.currency = CURRENCY;
diff --git a/modules/openxoutstreamBidAdapter.md b/modules/openxoutstreamBidAdapter.md
index a77b4560f97..16d66b92409 100644
--- a/modules/openxoutstreamBidAdapter.md
+++ b/modules/openxoutstreamBidAdapter.md
@@ -24,9 +24,8 @@ var adUnits = [
{
bidder: 'openxoutstream',
params: {
- unit: '53943996499',
+ unit: '540141567',
delDomain: 'se-demo-d.openx.net',
- publisher_page_url: 'yieldmo.com',
width: '300',
height: '250',
}
diff --git a/modules/quantcastBidAdapter.js b/modules/quantcastBidAdapter.js
index e6f4d27bdbb..79128a834a4 100644
--- a/modules/quantcastBidAdapter.js
+++ b/modules/quantcastBidAdapter.js
@@ -1,4 +1,5 @@
import * as utils from 'src/utils';
+import { ajax } from 'src/ajax';
import { registerBidder } from 'src/adapters/bidderFactory';
const BIDDER_CODE = 'quantcast';
@@ -69,7 +70,7 @@ export const spec = {
});
});
- const gdprConsent = bidderRequest ? bidderRequest.gdprConsent : {};
+ const gdprConsent = (bidderRequest && bidderRequest.gdprConsent) ? bidderRequest.gdprConsent : {};
// Request Data Format can be found at https://wiki.corp.qc/display/adinf/QCX
const requestData = {
@@ -157,6 +158,10 @@ export const spec = {
});
return bidResponsesList;
+ },
+ onTimeout(timeoutData) {
+ const url = `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb_notify?type=timeout`;
+ ajax(url, null, null);
}
};
diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js
index c8616894826..14143f5f21d 100644
--- a/modules/rivrAnalyticsAdapter.js
+++ b/modules/rivrAnalyticsAdapter.js
@@ -1,11 +1,12 @@
import {ajax} from 'src/ajax';
-import includes from 'core-js/library/fn/array/includes';
import adapter from 'src/AnalyticsAdapter';
+import find from 'core-js/library/fn/array/find';
import CONSTANTS from 'src/constants.json';
import adaptermanager from 'src/adaptermanager';
-import { logInfo, generateUUID } from 'src/utils';
+import { logInfo, generateUUID, timestamp } from 'src/utils';
const analyticsType = 'endpoint';
+const rivrUsrIdCookieKey = 'rvr_usr_id';
const DEFAULT_HOST = 'tracker.rivr.simplaex.com';
const DEFAULT_QUEUE_TIMEOUT = 4000;
@@ -23,18 +24,12 @@ let rivrAnalytics = Object.assign(adapter({analyticsType}), {
rivrAnalytics.context.queue.init();
}
if (rivrAnalytics.context.auctionObject) {
- rivrAnalytics.context.auctionObject = fulfillAuctionObject();
- saveUnoptimisedParams();
+ rivrAnalytics.context.auctionObject = createNewAuctionObject();
+ saveUnoptimisedAdUnits();
fetchLocalization();
}
handler = trackAuctionInit;
break;
- case CONSTANTS.EVENTS.BID_REQUESTED:
- handler = trackBidRequest;
- break;
- case CONSTANTS.EVENTS.BID_RESPONSE:
- handler = trackBidResponse;
- break;
case CONSTANTS.EVENTS.BID_WON:
handler = trackBidWon;
break;
@@ -56,7 +51,7 @@ export function sendAuction() {
removeEmptyProperties(rivrAnalytics.context.auctionObject);
let auctionObject = rivrAnalytics.context.auctionObject;
let req = Object.assign({}, {Auction: auctionObject});
- rivrAnalytics.context.auctionObject = fulfillAuctionObject();
+ rivrAnalytics.context.auctionObject = createNewAuctionObject();
logInfo('sending request to analytics => ', req);
ajax(
`http://${rivrAnalytics.context.host}/${rivrAnalytics.context.clientID}/auctions`,
@@ -98,46 +93,91 @@ function trackAuctionInit(args) {
rivrAnalytics.context.auctionObject.id = args.auctionId;
};
-function trackBidRequest(args) {
- setCurrentPublisherId(args);
- let bidRequest = args;
- rivrAnalytics.context.auctionObject.bidRequests.push(bidRequest);
-};
-
-function trackBidResponse(args) {
- let bidResponse = createBidResponse(args);
- rivrAnalytics.context.auctionObject.bidResponses.push(bidResponse);
+function trackBidWon(args) {
+ setWinningBidStatus(args);
};
-function trackBidWon(args) {
+function setWinningBidStatus(args) {
let auctionObject = rivrAnalytics.context.auctionObject;
- let auctionImpression = createAuctionImpression(args);
- auctionObject.imp.push(auctionImpression);
- assignBidWonStatusToResponse(args);
+ const bidderObjectForThisWonBid = find(auctionObject.bidders, (bidder) => {
+ return bidder.id === args.bidderCode;
+ });
+ if (bidderObjectForThisWonBid) {
+ const bidObjectForThisWonBid = find(bidderObjectForThisWonBid.bids, (bid) => {
+ return bid.impId === args.adUnitCode;
+ });
+ if (bidObjectForThisWonBid) {
+ bidObjectForThisWonBid.status = 1;
+ }
+ }
};
-function trackAuctionEnd(args) {
+export function trackAuctionEnd(args) {
rivrAnalytics.context.auctionTimeEnd = Date.now();
- fillBidResponsesOfUnrespondedBidRequests();
-};
-
-function trackBidTimeout(args) {
- return [args];
+ rivrAnalytics.context.auctionObject.bidders = buildBiddersArrayFromAuctionEnd(args);
+ rivrAnalytics.context.auctionObject.impressions = buildImpressionsArrayFromAuctionEnd(args);
};
-function setCurrentPublisherId(bidRequested) {
- let site = rivrAnalytics.context.auctionObject.site;
- let app = rivrAnalytics.context.auctionObject.app;
- let pubId = rivrAnalytics.context.pubId;
- if (!site.publisher.id || app.publisher.id) {
- if (pubId) {
- site.publisher.id = pubId;
- app.publisher.id = pubId;
- } else {
- site.publisher.id = bidRequested.bids[0].crumbs.pubcid;
- app.publisher.id = bidRequested.bids[0].crumbs.pubcid;
+function buildImpressionsArrayFromAuctionEnd(auctionEndEvent) {
+ return auctionEndEvent.adUnits.map((adUnit) => {
+ const impression = {};
+ impression.id = adUnit.code;
+ impression.adType = 'unknown';
+ impression.acceptedSizes = [];
+ const bidReceivedForThisAdUnit = find(auctionEndEvent.bidsReceived, (bidReceived) => {
+ return adUnit.code === bidReceived.adUnitCode;
+ });
+ if (adUnit.mediaTypes) {
+ if (adUnit.mediaTypes.banner) {
+ buildAdTypeDependentFieldsForImpression(impression, 'banner', adUnit, bidReceivedForThisAdUnit);
+ } else if (adUnit.mediaTypes.video) {
+ buildAdTypeDependentFieldsForImpression(impression, 'video', adUnit, bidReceivedForThisAdUnit);
+ }
}
+ return impression;
+ });
+}
+
+function buildAdTypeDependentFieldsForImpression(impression, adType, adUnit, bidReceivedForThisAdUnit) {
+ impression.adType = adType;
+ impression.acceptedSizes = adUnit.mediaTypes[adType].sizes.map((acceptedSize) => {
+ return {
+ w: acceptedSize[0],
+ h: acceptedSize[1]
+ };
+ });
+ if (bidReceivedForThisAdUnit) {
+ impression[adType] = {
+ w: bidReceivedForThisAdUnit.width,
+ h: bidReceivedForThisAdUnit.height
+ };
}
+}
+
+function buildBiddersArrayFromAuctionEnd(auctionEndEvent) {
+ return auctionEndEvent.bidderRequests.map((bidderRequest) => {
+ const bidder = {};
+ bidder.id = bidderRequest.bidderCode;
+ bidder.bids = bidderRequest.bids.map((bid) => {
+ const bidReceivedForThisRequest = find(auctionEndEvent.bidsReceived, (bidReceived) => {
+ return bidderRequest.bidderCode === bidReceived.bidderCode &&
+ bid.bidId === bidReceived.adId &&
+ bid.adUnitCode === bidReceived.adUnitCode;
+ });
+ return {
+ adomain: [''],
+ clearPrice: 0.0,
+ impId: bid.adUnitCode,
+ price: bidReceivedForThisRequest ? bidReceivedForThisRequest.cpm : 0.0,
+ status: 0
+ };
+ });
+ return bidder;
+ });
+}
+
+function trackBidTimeout(args) {
+ return [args];
};
export function fetchLocalization() {
@@ -158,70 +198,10 @@ export function setAuctionAbjectPosition(position) {
}
function getPlatformType() {
- if (navigator.userAgent.match(/mobile/i)) {
- return 'Mobile';
- } else if (navigator.userAgent.match(/iPad|Android|Touch/i)) {
- return 'Tablet';
+ if (navigator.userAgent.match(/mobile/i) || navigator.userAgent.match(/iPad|Android|Touch/i)) {
+ return 1;
} else {
- return 'Desktop';
- }
-};
-
-function createBidResponse(bidResponseEvent) {
- return {
- timestamp: bidResponseEvent.responseTimestamp,
- status: bidResponseEvent.getStatusCode(),
- total_duration: bidResponseEvent.timeToRespond,
- bidderId: null,
- bidder_name: bidResponseEvent.bidder,
- cur: bidResponseEvent.currency,
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 2,
- clear_price: bidResponseEvent.cpm,
- attr: [],
- crid: bidResponseEvent.creativeId,
- cid: null,
- id: null,
- adid: bidResponseEvent.adId,
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- }
-};
-
-function createSingleEmptyBidResponse(bidResponse) {
- return {
- timestamp: bidResponse.start,
- total_duration: null,
- bidderId: null,
- bidder_name: bidResponse.bidder,
- cur: null,
- response: 'noBid',
- seatbid: []
- }
-};
-
-function createAuctionImpression(bidWonEvent) {
- return {
- tagid: bidWonEvent.adUnitCode,
- displaymanager: null,
- displaymanagerver: null,
- secure: null,
- bidfloor: null,
- banner: {
- w: bidWonEvent.width,
- h: bidWonEvent.height,
- pos: null,
- expandable: [],
- api: []
- }
+ return 2;
}
};
@@ -314,75 +294,40 @@ function addHandlers(bannersIds) {
})
};
-function fulfillAuctionObject() {
- let newAuction = {
- id: null,
- timestamp: null,
- at: null,
- bcat: [],
- imp: [],
- app: {
- id: null,
- name: null,
- domain: window.location.href,
- bundle: null,
- cat: [],
- publisher: {
- id: null,
- name: null
- }
+export function createNewAuctionObject() {
+ const auction = {
+ id: '',
+ publisher: rivrAnalytics.context.clientID,
+ blockedCategories: [''],
+ timestamp: timestamp(),
+ user: {
+ id: rivrAnalytics.context.userId
},
site: {
- id: null,
- name: null,
- domain: window.location.href,
- cat: [],
- publisher: {
- id: null,
- name: null
- }
+ domain: window.location.host,
+ page: window.location.pathname,
+ categories: rivrAnalytics.context.siteCategories
},
+ impressions: [],
+ bidders: [],
device: {
- geo: {
- city: null,
- country: null,
- region: null,
- zip: null,
- type: null,
- metro: null
- },
- devicetype: getPlatformType(),
- osv: null,
- os: null,
- model: null,
- make: null,
- carrier: null,
- ip: null,
- didsha1: null,
- dpidmd5: null,
- ext: {
- uid: null
- }
- },
- user: {
- id: null,
- yob: null,
- gender: null,
+ userAgent: navigator.userAgent,
+ browser: '',
+ deviceType: getPlatformType()
},
- bidResponses: [],
- bidRequests: [],
+ 'ext.rivr.originalvalues': [],
'ext.rivr.optimiser': localStorage.getItem('rivr_should_optimise') || 'unoptimised',
modelVersion: localStorage.getItem('rivr_model_version') || null,
- 'ext.rivr.originalvalues': []
- };
- return newAuction;
+ }
+
+ return auction;
};
-function saveUnoptimisedParams() {
+export function saveUnoptimisedAdUnits() {
let units = rivrAnalytics.context.adUnits;
if (units) {
if (units.length > 0) {
- let allUnits = connectAllUnits(units);
+ let allUnits = concatAllUnits(units);
allUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
let configForBidder = fetchConfigForBidder(bid.bidder);
@@ -396,11 +341,8 @@ function saveUnoptimisedParams() {
}
};
-function connectAllUnits(units) {
- return units.reduce((acc, units) => {
- units.forEach((unit) => acc.push(unit))
- return acc
- }, []);
+export function concatAllUnits(units) {
+ return Array.prototype.concat.apply([], units);
}
export function createUnOptimisedParamsField(bid, config) {
@@ -474,41 +416,6 @@ export function ExpiringQueue(sendImpressions, sendAuction, ttl, log) {
}
};
-function assignBidWonStatusToResponse(wonBid) {
- let wonBidId = wonBid.adId;
- rivrAnalytics.context.auctionObject.bidResponses.forEach((response) => {
- if (response.seatbid.length > 0) {
- let bidObjectResponse = response.seatbid[0].bid[0];
- if (wonBidId === bidObjectResponse.adid) {
- bidObjectResponse.status = 1
- }
- }
- });
-};
-
-function fillBidResponsesOfUnrespondedBidRequests() {
- let unRespondedBidRequests = getAllUnrespondedBidRequests();
- unRespondedBidRequests.forEach((bid) => {
- let emptyBidResponse = createSingleEmptyBidResponse(bid);
- rivrAnalytics.context.auctionObject.bidResponses.push(emptyBidResponse);
- });
-};
-
-function getAllUnrespondedBidRequests() {
- let respondedBidIds = getAllRespondedBidIds();
- let bidRequests = rivrAnalytics.context.auctionObject.bidRequests;
- let allNotRespondedBidRequests = bidRequests.reduce((cache, requestBidder) => {
- let notRespondedBids = requestBidder.bids.filter((bid) => !includes(respondedBidIds, bid.bidId));
- notRespondedBids.forEach((bid) => bid.start = requestBidder.start);
- return cache.concat(notRespondedBids);
- }, []);
- return allNotRespondedBidRequests;
-};
-
-function getAllRespondedBidIds() {
- return rivrAnalytics.context.auctionObject.bidResponses.map((response) => response.seatbid[0].bid[0].adid);
-};
-
function removeEmptyProperties(obj) {
Object.keys(obj).forEach(function(key) {
if (obj[key] && typeof obj[key] === 'object') removeEmptyProperties(obj[key])
@@ -516,6 +423,16 @@ function removeEmptyProperties(obj) {
});
};
+function getCookie(name) {
+ var value = '; ' + document.cookie;
+ var parts = value.split('; ' + name + '=');
+ if (parts.length == 2) return parts.pop().split(';').shift();
+}
+
+function storeAndReturnRivrUsrIdCookie() {
+ return document.cookie = 'rvr_usr_id=' + generateUUID();
+}
+
// save the base class function
rivrAnalytics.originEnableAnalytics = rivrAnalytics.enableAnalytics;
@@ -527,10 +444,11 @@ rivrAnalytics.enableAnalytics = (config) => {
copiedUnits = JSON.parse(stringifiedAdUnits);
}
rivrAnalytics.context = {
+ userId: getCookie(rivrUsrIdCookieKey) || storeAndReturnRivrUsrIdCookie(),
host: config.options.host || DEFAULT_HOST,
- pubId: config.options.pubId,
auctionObject: {},
adUnits: copiedUnits,
+ siteCategories: config.options.siteCategories || [],
clientID: config.options.clientID,
authToken: config.options.authToken,
queue: new ExpiringQueue(sendImpressions, sendAuction, config.options.queueTimeout || DEFAULT_QUEUE_TIMEOUT)
diff --git a/modules/rivrAnalyticsAdapter.md b/modules/rivrAnalyticsAdapter.md
new file mode 100644
index 00000000000..787034e362e
--- /dev/null
+++ b/modules/rivrAnalyticsAdapter.md
@@ -0,0 +1,13 @@
+# Overview
+
+Module Name: Rivr Analytics Adapter
+
+Module Type: Analytics Adapter
+
+Maintainer: rnd@simplaex.com
+
+# Description
+
+Analytics adapter for www.rivr.ai.
+
+Contact support@simplaex.com for information and support.
diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js
index e4a30782dbe..0be3887637d 100644
--- a/modules/rtbhouseBidAdapter.js
+++ b/modules/rtbhouseBidAdapter.js
@@ -43,9 +43,12 @@ export const spec = {
const request = {
id: validBidRequests[0].auctionId,
imp: validBidRequests.map(slot => mapImpression(slot)),
- site: mapSite(validBidRequests),
+ site: mapSite(validBidRequests, bidderRequest),
cur: DEFAULT_CURRENCY_ARR,
- test: validBidRequests[0].params.test || 0
+ test: validBidRequests[0].params.test || 0,
+ source: {
+ tid: validBidRequests[0].transactionId
+ }
};
if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
const consentStr = (bidderRequest.gdprConsent.consentString)
@@ -89,12 +92,19 @@ registerBidder(spec);
* @returns {object} Imp by OpenRTB 2.5 §3.2.4
*/
function mapImpression(slot) {
- return {
+ const imp = {
id: slot.bidId,
banner: mapBanner(slot),
native: mapNative(slot),
tagid: slot.adUnitCode.toString()
};
+
+ const bidfloor = parseFloat(slot.params.bidfloor);
+ if (bidfloor) {
+ imp.bidfloor = bidfloor
+ }
+
+ return imp;
}
/**
@@ -118,9 +128,10 @@ function mapBanner(slot) {
/**
* @param {object} slot Ad Unit Params by Prebid
+ * @param {object} bidderRequest by Prebid
* @returns {object} Site by OpenRTB 2.5 §3.2.13
*/
-function mapSite(slot) {
+function mapSite(slot, bidderRequest) {
const pubId = slot && slot.length > 0
? slot[0].params.publisherId
: 'unknown';
@@ -128,7 +139,7 @@ function mapSite(slot) {
publisher: {
id: pubId.toString(),
},
- page: utils.getTopWindowUrl(),
+ page: bidderRequest.refererInfo.referer,
name: utils.getOrigin()
}
}
diff --git a/modules/rtbhouseBidAdapter.md b/modules/rtbhouseBidAdapter.md
index a2d7e2aedda..c847e688941 100644
--- a/modules/rtbhouseBidAdapter.md
+++ b/modules/rtbhouseBidAdapter.md
@@ -7,7 +7,7 @@ Maintainer: prebid@rtbhouse.com
# Description
Connects to RTB House unique demand.
-Banner formats are supported.
+Banner and native formats are supported.
Unique publisherId is required.
Please reach out to pmp@rtbhouse.com to receive your own
@@ -23,7 +23,8 @@ Please reach out to pmp@rtbhouse.com to receive your own
bidder: "rtbhouse",
params: {
region: 'prebid-eu',
- publisherId: 'PREBID_TEST_ID'
+ publisherId: 'PREBID_TEST_ID',
+ bidfloor: 0.01 // optional
}
}
]
@@ -50,6 +51,7 @@ Please reach out to pmp@rtbhouse.com to receive your own
params: {
region: 'prebid-eu',
publisherId: 'PREBID_TEST_ID'
+ bidfloor: 0.01 // optional
}
}
]
diff --git a/modules/undertoneBidAdapter.js b/modules/undertoneBidAdapter.js
index dd99df1fc7e..6d4ced88ba1 100644
--- a/modules/undertoneBidAdapter.js
+++ b/modules/undertoneBidAdapter.js
@@ -2,11 +2,44 @@
* Adapter to send bids to Undertone
*/
-import * as utils from 'src/utils';
+import * as urlUtils from 'src/url';
import { registerBidder } from 'src/adapters/bidderFactory';
const BIDDER_CODE = 'undertone';
const URL = '//hb.undertone.com/hb';
+const FRAME_USER_SYNC = '//cdn.undertone.com/js/usersync.html';
+const PIXEL_USER_SYNC_1 = '//usr.undertone.com/userPixel/syncOne?id=1&of=2';
+const PIXEL_USER_SYNC_2 = '//usr.undertone.com/userPixel/syncOne?id=2&of=2';
+
+function getCanonicalUrl() {
+ try {
+ let doc = window.top.document;
+ let element = doc.querySelector("link[rel='canonical']");
+ if (element !== null) {
+ return element.href;
+ }
+ } catch (e) {
+ }
+ return null;
+}
+
+function extractDomainFromHost(pageHost) {
+ let domain = null;
+ try {
+ let domains = /[-\w]+\.([-\w]+|[-\w]{3,}|[-\w]{1,3}\.[-\w]{2})$/i.exec(pageHost);
+ if (domains != null && domains.length > 0) {
+ domain = domains[0];
+ for (let i = 1; i < domains.length; i++) {
+ if (domains[i].length > domain.length) {
+ domain = domains[i];
+ }
+ }
+ }
+ } catch (e) {
+ domain = null;
+ }
+ return domain;
+}
export const spec = {
code: BIDDER_CODE,
@@ -16,21 +49,14 @@ export const spec = {
return true;
}
},
- buildRequests: function(validBidRequests) {
+ buildRequests: function(validBidRequests, bidderRequest) {
const payload = {
'x-ut-hb-params': []
};
- const location = utils.getTopWindowLocation();
- let domains = /[-\w]+\.([-\w]+|[-\w]{3,}|[-\w]{1,3}\.[-\w]{2})$/i.exec(location.host);
- let domain = null;
- if (domains != null && domains.length > 0) {
- domain = domains[0];
- for (let i = 1; i < domains.length; i++) {
- if (domains[i].length > domain.length) {
- domain = domains[i];
- }
- }
- }
+ const referer = bidderRequest.refererInfo.referer;
+ const hostname = urlUtils.parse(referer).hostname;
+ let domain = extractDomainFromHost(hostname);
+ const pageUrl = getCanonicalUrl() || referer;
const pubid = validBidRequests[0].params.publisherId;
const REQ_URL = `${URL}?pid=${pubid}&domain=${domain}`;
@@ -39,7 +65,7 @@ export const spec = {
const bid = {
bidRequestId: bidReq.bidId,
hbadaptor: 'prebid',
- url: location.href,
+ url: pageUrl,
domain: domain,
placementId: bidReq.params.placementId != undefined ? bidReq.params.placementId : null,
publisherId: bidReq.params.publisherId,
@@ -78,6 +104,29 @@ export const spec = {
});
}
return bids;
+ },
+ getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
+ const syncs = [];
+ if (gdprConsent && gdprConsent.gdprApplies === true) {
+ return syncs;
+ }
+
+ if (syncOptions.iframeEnabled) {
+ syncs.push({
+ type: 'iframe',
+ url: FRAME_USER_SYNC
+ });
+ } else if (syncOptions.pixelEnabled) {
+ syncs.push({
+ type: 'image',
+ url: PIXEL_USER_SYNC_1
+ },
+ {
+ type: 'image',
+ url: PIXEL_USER_SYNC_2
+ });
+ }
+ return syncs;
}
};
registerBidder(spec);
diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js
index cdcab0c705a..5843ce9d339 100644
--- a/modules/yieldoneBidAdapter.js
+++ b/modules/yieldoneBidAdapter.js
@@ -1,6 +1,7 @@
import * as utils from 'src/utils';
import {config} from 'src/config';
import {registerBidder} from 'src/adapters/bidderFactory';
+import { BANNER, VIDEO } from 'src/mediaTypes';
const BIDDER_CODE = 'yieldone';
const ENDPOINT_URL = '//y.one.impact-ad.jp/h_bid';
@@ -9,15 +10,13 @@ const USER_SYNC_URL = '//y.one.impact-ad.jp/push_sync';
export const spec = {
code: BIDDER_CODE,
aliases: ['y1'],
+ supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid: function(bid) {
return !!(bid.params.placementId);
},
buildRequests: function(validBidRequests) {
return validBidRequests.map(bidRequest => {
const params = bidRequest.params;
- const sizes = utils.parseSizesInput(bidRequest.sizes)[0];
- const width = sizes.split('x')[0];
- const height = sizes.split('x')[1];
const placementId = params.placementId;
const cb = Math.floor(Math.random() * 99999999999);
const referrer = encodeURIComponent(utils.getTopWindowUrl());
@@ -25,13 +24,24 @@ export const spec = {
const payload = {
v: 'hb1',
p: placementId,
- w: width,
- h: height,
cb: cb,
r: referrer,
uid: bidId,
t: 'i'
};
+
+ const videoMediaType = utils.deepAccess(bidRequest, 'mediaTypes.video');
+ if (bidRequest.mediaType === VIDEO || videoMediaType) {
+ const sizes = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize') || bidRequest.sizes;
+ const size = utils.parseSizesInput(sizes)[0];
+ payload.w = size.split('x')[0];
+ payload.h = size.split('x')[1];
+ } else if ((utils.isEmpty(bidRequest.mediaType) && utils.isEmpty(bidRequest.mediaTypes)) ||
+ (bidRequest.mediaType === BANNER || (bidRequest.mediaTypes && bidRequest.mediaTypes[BANNER]))) {
+ const sizes = utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes;
+ payload.sz = utils.parseSizesInput(sizes).join(',');
+ }
+
return {
method: 'GET',
url: ENDPOINT_URL,
@@ -47,12 +57,12 @@ export const spec = {
const height = response.height || 0;
const cpm = response.cpm * 1000 || 0;
if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) {
- const dealId = response.dealid || '';
+ const dealId = response.dealId || '';
const currency = response.currency || 'JPY';
const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
const referrer = utils.getTopWindowUrl();
const bidResponse = {
- requestId: bidRequest.data.uid,
+ requestId: response.uid,
cpm: cpm,
width: response.width,
height: response.height,
@@ -61,9 +71,17 @@ export const spec = {
currency: currency,
netRevenue: netRevenue,
ttl: config.getConfig('_bidderTimeout'),
- referrer: referrer,
- ad: response.adTag
+ referrer: referrer
};
+
+ if (response.adTag) {
+ bidResponse.mediaType = BANNER;
+ bidResponse.ad = response.adTag;
+ } else if (response.adm) {
+ bidResponse.mediaType = VIDEO;
+ bidResponse.vastXml = response.adm;
+ }
+
bidResponses.push(bidResponse);
}
return bidResponses;
diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md
index b154a2ee781..1414d4e464f 100644
--- a/modules/yieldoneBidAdapter.md
+++ b/modules/yieldoneBidAdapter.md
@@ -10,20 +10,46 @@ Maintainer: y1dev@platform-one.co.jp
Connect to YIELDONE for bids.
-THE YIELDONE adapter requires setup and approval from the YIELDONE team. Please reach out to your account team or y1s@platform-one.co.jp for more information.
+THE YIELDONE adapter requires setup and approval from the YIELDONE team.
+Please reach out to your account team or y1s@platform-one.co.jp for more information.
+
+Note: THE YIELDONE adapter do not support "multi-format" scenario... if both
+banner and video are specified as mediatypes, YIELDONE will treat it as a video unit.
# Test Parameters
-```
- var adUnits = [{
- code: 'banner-ad-div',
- sizes: [[300, 250]],
- bids: [{
- bidder: 'yieldone',
- params: {
- placementId: '44082'
- }
- }]
- }];
+```javascript
+var adUnits = [
+ // Banner adUnit
+ {
+ code: 'banner-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [336, 280]]
+ }
+ },
+ bids: [{
+ bidder: 'yieldone',
+ params: {
+ placementId: '36891'
+ }
+ }]
+ },
+ // Video adUnit
+ {
+ code: 'video-div',
+ mediaTypes: {
+ video: {
+ playerSize: [[640, 480]],
+ context: 'outstream'
+ },
+ },
+ bids: [{
+ bidder: 'yieldone',
+ params: {
+ placementId: '41993'
+ }
+ }]
+ }
```
### Configuration
diff --git a/package.json b/package.json
index a53085fa062..288d970f842 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prebid.js",
- "version": "1.30.0-pre",
+ "version": "1.31.0-pre",
"description": "Header Bidding Management Library",
"main": "src/prebid.js",
"scripts": {
diff --git a/src/auction.js b/src/auction.js
index 61c403e7ff5..221cd519815 100644
--- a/src/auction.js
+++ b/src/auction.js
@@ -110,7 +110,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
function getProperties() {
return {
auctionId: _auctionId,
- auctionStart: _auctionStart,
+ timestamp: _auctionStart,
auctionEnd: _auctionEnd,
auctionStatus: _auctionStatus,
adUnits: _adUnits,
diff --git a/src/native.js b/src/native.js
index b4d2d959b70..c9d274ddccd 100644
--- a/src/native.js
+++ b/src/native.js
@@ -147,7 +147,7 @@ export function fireNativeTrackers(message, adObject) {
}
/**
- * Gets native targeting key-value paris
+ * Gets native targeting key-value pairs
* @param {Object} bid
* @return {Object} targeting
*/
@@ -163,7 +163,7 @@ export function getNativeTargeting(bid) {
value = value.url;
}
- if (key) {
+ if (key && value) {
keyValues[key] = value;
}
});
diff --git a/src/targeting.js b/src/targeting.js
index dcd59f362c6..30407994b8e 100644
--- a/src/targeting.js
+++ b/src/targeting.js
@@ -35,20 +35,11 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback) {
// filter top bid for each bucket by bidder
Object.keys(buckets).forEach(bucketKey => {
let bidsByBidder = groupBy(buckets[bucketKey], 'bidderCode');
- Object.keys(bidsByBidder).forEach(key => bids.push(bidsByBidder[key].reduce(highestCpmCallback, getEmptyBid())));
+ Object.keys(bidsByBidder).forEach(key => bids.push(bidsByBidder[key].reduce(highestCpmCallback)));
});
return bids;
}
-function getEmptyBid(adUnitCode) {
- return {
- adUnitCode: adUnitCode,
- cpm: 0,
- adserverTargeting: {},
- timeToRespond: 0
- };
-}
-
/**
* @typedef {Object.} targeting
* @property {string} targeting_key
@@ -222,7 +213,7 @@ export function newTargeting(auctionManager) {
.filter(uniques)
.map(adUnitCode => bidsReceived
.filter(bid => bid.adUnitCode === adUnitCode ? bid : null)
- .reduce(getHighestCpm, getEmptyBid(adUnitCode)));
+ .reduce(getHighestCpm));
};
/**
diff --git a/src/utils.js b/src/utils.js
index 77dfe10c918..93b19485dfe 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -66,10 +66,22 @@ exports.getUniqueIdentifierStr = _getUniqueIdentifierStr;
*/
exports.generateUUID = function generateUUID(placeholder) {
return placeholder
- ? (placeholder ^ Math.random() * 16 >> placeholder / 4).toString(16)
+ ? (placeholder ^ _getRandomData() >> placeholder / 4).toString(16)
: ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, generateUUID);
};
+/**
+ * Returns random data using the Crypto API if available and Math.random if not
+ * Method is from https://gist.github.com/jed/982883 like generateUUID, direct link https://gist.github.com/jed/982883#gistcomment-45104
+ */
+function _getRandomData() {
+ if (window && window.crypto && window.crypto.getRandomValues) {
+ return crypto.getRandomValues(new Uint8Array(1))[0] % 16;
+ } else {
+ return Math.random() * 16;
+ }
+}
+
exports.getBidIdParameter = function (key, paramsObj) {
if (paramsObj && paramsObj[key]) {
return paramsObj[key];
diff --git a/test/spec/modules/adikteevBidAdapter_spec.js b/test/spec/modules/adikteevBidAdapter_spec.js
new file mode 100644
index 00000000000..243cbe2a9c5
--- /dev/null
+++ b/test/spec/modules/adikteevBidAdapter_spec.js
@@ -0,0 +1,235 @@
+import {expect} from 'chai';
+import {
+ ENDPOINT_URL,
+ ENDPOINT_URL_STAGING,
+ setstagingEnvironmentSwitch,
+ spec,
+ stagingEnvironmentSwitch,
+ USER_SYNC_IFRAME_URL,
+ USER_SYNC_IFRAME_URL_STAGING,
+ USER_SYNC_IMAGE_URL,
+ USER_SYNC_IMAGE_URL_STAGING,
+} from 'modules/adikteevBidAdapter';
+import {newBidder} from 'src/adapters/bidderFactory';
+import * as utils from '../../../src/utils';
+
+describe('adikteevBidAdapter', () => {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', () => {
+ it('exists and is a function', () => {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ it('exists and is a function', () => {
+ expect(setstagingEnvironmentSwitch).to.exist.and.to.be.a('function');
+ });
+ it('exists and is correctly set', () => {
+ expect(stagingEnvironmentSwitch).to.exist.and.to.equal(false);
+ });
+ });
+
+ describe('isBidRequestValid', () => {
+ it('should return true when required params found', () => {
+ const validBid = {
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ };
+ expect(spec.isBidRequestValid(validBid)).to.equal(true);
+ });
+
+ it('should mutate stagingEnvironmentSwitch when required params found', () => {
+ const withstagingEnvironmentSwitch = {
+ params: {
+ stagingEnvironment: true,
+ },
+ };
+ spec.isBidRequestValid(withstagingEnvironmentSwitch);
+ expect(stagingEnvironmentSwitch).to.equal(true);
+ setstagingEnvironmentSwitch(false);
+ });
+
+ it('should return false when required params are invalid', () => {
+ expect(spec.isBidRequestValid({
+ bidder: '', // invalid bidder
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ bidder: 'adikteev',
+ params: {
+ placementId: '', // invalid placementId
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750, 200]]
+ }
+ },
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ bidder: 'adikteev',
+ params: {
+ placementId: 12345,
+ bidFloorPrice: 0.1,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[750]] // invalid size
+ }
+ },
+ })).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', () => {
+ const validBidRequests = [];
+ const bidderRequest = {};
+ const serverRequest = spec.buildRequests(validBidRequests, bidderRequest);
+ it('creates a request object with correct method, url and data', () => {
+ expect(serverRequest).to.exist.and.have.all.keys(
+ 'method',
+ 'url',
+ 'data',
+ );
+ expect(serverRequest.method).to.equal('POST');
+ expect(serverRequest.url).to.equal(ENDPOINT_URL);
+
+ let requestData = JSON.parse(serverRequest.data);
+ expect(requestData).to.exist.and.have.all.keys(
+ 'validBidRequests',
+ 'bidderRequest',
+ 'userAgent',
+ 'screen',
+ 'language',
+ 'cookies',
+ // 'refererInfo',
+ // 'currency',
+ 'prebidUpdateVersion',
+ );
+ expect(requestData.validBidRequests).to.deep.equal(validBidRequests);
+ expect(requestData.bidderRequest).to.deep.equal(bidderRequest);
+ expect(requestData.userAgent).to.deep.equal(navigator.userAgent);
+ expect(requestData.screen.width).to.deep.equal(window.screen.width);
+ expect(requestData.screen.height).to.deep.equal(window.screen.height);
+ expect(requestData.language).to.deep.equal(navigator.language);
+ expect(requestData.prebidUpdateVersion).to.deep.equal('1.29.0');
+ });
+
+ describe('staging environment', () => {
+ setstagingEnvironmentSwitch(true);
+ const serverRequest = spec.buildRequests(validBidRequests, bidderRequest);
+ expect(serverRequest.url).to.equal(ENDPOINT_URL_STAGING);
+ setstagingEnvironmentSwitch(false);
+ });
+ });
+
+ describe('interpretResponse', () => {
+ it('bid objects from response', () => {
+ const serverResponse =
+ {
+ body: [
+ {
+ cpm: 1,
+ width: 300,
+ height: 250,
+ ad: '',
+ ttl: 360,
+ creativeId: 123,
+ netRevenue: false,
+ currency: 'EUR',
+ }
+ ]
+ };
+ const payload = {
+ validBidRequests: [{
+ bidId: '2ef7bb021ac847'
+ }],
+ };
+ const bidRequests = {
+ method: 'POST',
+ url: stagingEnvironmentSwitch ? ENDPOINT_URL_STAGING : ENDPOINT_URL,
+ data: JSON.stringify(payload),
+ };
+ const bidResponses = spec.interpretResponse(serverResponse, bidRequests);
+ expect(bidResponses).to.be.an('array').that.is.not.empty; // yes, syntax is correct
+ expect(bidResponses[0]).to.have.all.keys(
+ 'requestId',
+ 'cpm',
+ 'width',
+ 'height',
+ 'ad',
+ 'ttl',
+ 'creativeId',
+ 'netRevenue',
+ 'currency',
+ );
+
+ expect(bidResponses[0].requestId).to.equal(payload.validBidRequests[0].bidId);
+ expect(bidResponses[0].cpm).to.equal(serverResponse.body[0].cpm);
+ expect(bidResponses[0].width).to.equal(serverResponse.body[0].width);
+ expect(bidResponses[0].height).to.equal(serverResponse.body[0].height);
+ expect(bidResponses[0].ad).to.equal(serverResponse.body[0].ad);
+ expect(bidResponses[0].ttl).to.equal(serverResponse.body[0].ttl);
+ expect(bidResponses[0].creativeId).to.equal(serverResponse.body[0].creativeId);
+ expect(bidResponses[0].netRevenue).to.equal(serverResponse.body[0].netRevenue);
+ expect(bidResponses[0].currency).to.equal(serverResponse.body[0].currency);
+ });
+ });
+
+ describe('getUserSyncs', () => {
+ expect(spec.getUserSyncs({
+ iframeEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL
+ }]);
+
+ expect(spec.getUserSyncs({
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL
+ }]);
+
+ expect(spec.getUserSyncs({
+ iframeEnabled: true,
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL
+ }, {
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL
+ }]);
+
+ describe('staging environment', () => {
+ setstagingEnvironmentSwitch(true);
+ expect(spec.getUserSyncs({
+ iframeEnabled: true,
+ pixelEnabled: true
+ }, [{}])).to.deep.equal([{
+ type: 'iframe',
+ url: USER_SYNC_IFRAME_URL_STAGING
+ }, {
+ type: 'image',
+ url: USER_SYNC_IMAGE_URL_STAGING
+ }]);
+ setstagingEnvironmentSwitch(false);
+ });
+ });
+});
diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js
index 9be87ac8628..5e41c1c9544 100644
--- a/test/spec/modules/appnexusBidAdapter_spec.js
+++ b/test/spec/modules/appnexusBidAdapter_spec.js
@@ -561,5 +561,15 @@ describe('AppNexusAdapter', function () {
bidderRequest.bids[0].renderer.options
);
});
+
+ it('should add deal_priority and deal_code', function() {
+ let responseWithDeal = deepClone(response);
+ responseWithDeal.tags[0].ads[0].deal_priority = 'high';
+ responseWithDeal.tags[0].ads[0].deal_code = '123';
+
+ let bidderRequest;
+ let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest});
+ expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']);
+ });
});
});
diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js
new file mode 100644
index 00000000000..dd34582e22d
--- /dev/null
+++ b/test/spec/modules/emx_digitalBidAdapter_spec.js
@@ -0,0 +1,338 @@
+import { expect } from 'chai';
+import { spec } from 'modules/emx_digitalBidAdapter';
+import * as utils from 'src/utils';
+import { newBidder } from 'src/adapters/bidderFactory';
+
+describe('emx_digital Adapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('required function', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': '1d1a01234a475'
+ };
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should contain tagid param', function () {
+ expect(spec.isBidRequestValid({
+ params: {}
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ params: {
+ tagid: ''
+ }
+ })).to.equal(false);
+ expect(spec.isBidRequestValid({
+ params: {
+ tagid: '123'
+ }
+ })).to.equal(true);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [{
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ]
+ }
+ },
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec'
+ }, {
+ 'bidder': 'emx_digital',
+ 'params': {
+ 'tagid': '25251'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ]
+ }
+ },
+ 'sizes': [
+ [300, 250],
+ [300, 600]
+ ],
+ 'bidId': '30b31c2501de1e',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec'
+ }];
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ };
+ bidderRequest.bids = bidRequests
+
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ expect(request.method).to.equal('POST');
+ });
+
+ it('contains the correct options', function () {
+ expect(request.options.withCredentials).to.equal(true);
+ });
+
+ it('sends contains a properly formatted endpoint url', function () {
+ const url = request.url.split('?');
+ const queryParams = url[1].split('&');
+ expect(queryParams[0]).to.match(new RegExp('^t=\d*', 'g'));
+ expect(queryParams[1]).to.match(new RegExp('^ts=\d*', 'g'));
+ });
+
+ it('builds request properly', function () {
+ const data = JSON.parse(request.data);
+
+ expect(Array.isArray(data.imp)).to.equal(true);
+ expect(data.id).to.equal(bidderRequest.auctionId);
+ expect(data.imp.length).to.equal(2);
+ expect(data.imp[0].id).to.equal('30b31c2501de1e');
+ expect(data.imp[0].tid).to.equal('d7b773de-ceaa-484d-89ca-d9f51b8d61ec');
+ expect(data.imp[0].tagid).to.equal('25251');
+ expect(data.imp[0].secure).to.equal(0);
+ });
+
+ it('builds with bid floor', function() {
+ const bidRequestWithBidFloor = utils.deepClone(bidRequests);
+ bidRequestWithBidFloor[0].params.bidfloor = 1;
+ const requestWithFloor = spec.buildRequests(bidRequestWithBidFloor, bidderRequest);
+ const data = JSON.parse(requestWithFloor.data);
+ expect(data.imp[0].bidfloor).to.equal(bidRequestWithBidFloor[0].params.bidfloor);
+ })
+
+ it('properly sends site information and protocol', function () {
+ let mock = sinon.stub(utils, 'getTopWindowLocation').callsFake(() => {
+ return {
+ protocol: 'https:',
+ host: 'example.com',
+ href: 'https://example.com/index.html'
+ };
+ });
+
+ let request;
+
+ request = spec.buildRequests(bidRequests, bidderRequest);
+ request = JSON.parse(request.data);
+ expect(request.site.domain).to.equal('example.com');
+ expect(request.site.page).to.equal('https://example.com/index.html');
+ expect(request.imp[0].secure).to.equal(1);
+
+ mock.restore();
+ })
+
+ it('builds correctly formatted request banner object', function () {
+ let request;
+
+ let bidRequestWithBanner = utils.deepClone(bidRequests);
+
+ request = spec.buildRequests(bidRequestWithBanner, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.imp[0].banner.w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]);
+ expect(data.imp[0].banner.h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]);
+ expect(data.imp[0].banner.format[0].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]);
+ expect(data.imp[0].banner.format[0].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]);
+ expect(data.imp[0].banner.format[1].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][0]);
+ expect(data.imp[0].banner.format[1].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][1]);
+ })
+
+ it('shouldn\'t contain a user obj without GDPR information', function () {
+ let request = spec.buildRequests(bidRequests, bidderRequest)
+ request = JSON.parse(request.data)
+ expect(request).to.not.have.property('user');
+ });
+
+ it('should have the right gdpr info when enabled', function () {
+ let consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A==';
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ 'gdprConsent': {
+ 'consentString': consentString,
+ 'gdprApplies': true
+ }
+ };
+ bidderRequest.bids = bidRequests
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ request = JSON.parse(request.data)
+ expect(request.regs.ext).to.have.property('gdpr', 1);
+ expect(request.user.ext).to.have.property('consent', 'OIJSZsOAFsABAB8EMXZZZZZ+A==');
+ });
+
+ it('should\'t contain consent string if gdpr isn\'t applied', function () {
+ let bidderRequest = {
+ 'bidderCode': 'emx_digital',
+ 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c',
+ 'bidderRequestId': '22edbae3120bf6',
+ 'timeout': 1500,
+ 'gdprConsent': {
+ 'gdprApplies': false
+ }
+ };
+ bidderRequest.bids = bidRequests
+ let request = spec.buildRequests(bidRequests, bidderRequest);
+
+ request = JSON.parse(request.data)
+ expect(request.regs.ext).to.have.property('gdpr', 0);
+ expect(request).to.not.have.property('user');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const serverResponse = {
+ 'id': '12819a18-56e1-4256-b836-b69a10202668',
+ 'seatbid': [{
+ 'bid': [{
+ 'adid': '123456abcde',
+ 'adm': '',
+ 'crid': '3434abab34',
+ 'h': 250,
+ 'id': '987654321cba',
+ 'price': 0.5,
+ 'ttl': 300,
+ 'w': 300
+ }],
+ 'seat': '1356'
+ }, {
+ 'bid': [{
+ 'adid': '123456abcdf',
+ 'adm': '',
+ 'crid': '3434abab35',
+ 'h': 600,
+ 'id': '987654321cba',
+ 'price': 0.5,
+ 'ttl': 300,
+ 'w': 300
+ }]
+ }]
+ };
+
+ const expectedResponse = [{
+ 'requestId': '12819a18-56e1-4256-b836-b69a10202668',
+ 'cpm': 0.5,
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '3434abab34',
+ 'dealId': null,
+ 'currency': 'USD',
+ 'netRevneue': true,
+ 'mediaType': 'banner',
+ 'ad': '',
+ 'ttl': 300
+ }, {
+ 'requestId': '12819a18-56e1-4256-b836-b69a10202668',
+ 'cpm': 0.7,
+ 'width': 300,
+ 'height': 600,
+ 'creativeId': '3434abab35',
+ 'dealId': null,
+ 'currency': 'USD',
+ 'netRevneue': true,
+ 'mediaType': 'banner',
+ 'ad': '',
+ 'ttl': 300
+ }];
+
+ it('should properly format bid response', function () {
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(Object.keys(result[0]).length).to.equal(Object.keys(expectedResponse[0]).length);
+ expect(Object.keys(result[0]).requestId).to.equal(Object.keys(expectedResponse[0]).requestId);
+ expect(Object.keys(result[0]).bidderCode).to.equal(Object.keys(expectedResponse[0]).bidderCode);
+ expect(Object.keys(result[0]).cpm).to.equal(Object.keys(expectedResponse[0]).cpm);
+ expect(Object.keys(result[0]).creativeId).to.equal(Object.keys(expectedResponse[0]).creativeId);
+ expect(Object.keys(result[0]).width).to.equal(Object.keys(expectedResponse[0]).width);
+ expect(Object.keys(result[0]).height).to.equal(Object.keys(expectedResponse[0]).height);
+ expect(Object.keys(result[0]).ttl).to.equal(Object.keys(expectedResponse[0]).ttl);
+ expect(Object.keys(result[0]).adId).to.equal(Object.keys(expectedResponse[0]).adId);
+ expect(Object.keys(result[0]).currency).to.equal(Object.keys(expectedResponse[0]).currency);
+ expect(Object.keys(result[0]).netRevenue).to.equal(Object.keys(expectedResponse[0]).netRevenue);
+ expect(Object.keys(result[0]).ad).to.equal(Object.keys(expectedResponse[0]).ad);
+ });
+
+ it('should return multiple bids', function () {
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(Array.isArray(result.seatbid))
+
+ const ad0 = result[0];
+ const ad1 = result[1];
+ expect(ad0.ad).to.equal(serverResponse.seatbid[0].bid[0].adm);
+ expect(ad0.cpm).to.equal(serverResponse.seatbid[0].bid[0].price);
+ expect(ad0.creativeId).to.equal(serverResponse.seatbid[0].bid[0].crid);
+ expect(ad0.currency).to.equal('USD');
+ expect(ad0.height).to.equal(serverResponse.seatbid[0].bid[0].h);
+ expect(ad0.mediaType).to.equal('banner');
+ expect(ad0.netRevenue).to.equal(true);
+ expect(ad0.requestId).to.equal(serverResponse.seatbid[0].bid[0].id);
+ expect(ad0.ttl).to.equal(300);
+ expect(ad0.width).to.equal(serverResponse.seatbid[0].bid[0].w);
+
+ expect(ad1.ad).to.equal(serverResponse.seatbid[1].bid[0].adm);
+ expect(ad1.cpm).to.equal(serverResponse.seatbid[1].bid[0].price);
+ expect(ad1.creativeId).to.equal(serverResponse.seatbid[1].bid[0].crid);
+ expect(ad1.currency).to.equal('USD');
+ expect(ad1.height).to.equal(serverResponse.seatbid[1].bid[0].h);
+ expect(ad1.mediaType).to.equal('banner');
+ expect(ad1.netRevenue).to.equal(true);
+ expect(ad1.requestId).to.equal(serverResponse.seatbid[1].bid[0].id);
+ expect(ad1.ttl).to.equal(300);
+ expect(ad1.width).to.equal(serverResponse.seatbid[1].bid[0].w);
+ });
+
+ it('handles nobid responses', function () {
+ let serverResponse = {
+ 'bids': []
+ };
+
+ let result = spec.interpretResponse({
+ body: serverResponse
+ });
+ expect(result.length).to.equal(0);
+ });
+ });
+});
diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js
new file mode 100644
index 00000000000..f4401dfe677
--- /dev/null
+++ b/test/spec/modules/gridBidAdapter_spec.js
@@ -0,0 +1,299 @@
+import { expect } from 'chai';
+import { spec } from 'modules/gridBidAdapter';
+import { newBidder } from 'src/adapters/bidderFactory';
+
+describe('TheMediaGrid Adapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ };
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when required params are not passed', function () {
+ let bid = Object.assign({}, bid);
+ delete bid.params;
+ bid.params = {
+ 'uid': 0
+ };
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ function parseRequest(url) {
+ const res = {};
+ url.split('&').forEach((it) => {
+ const couple = it.split('=');
+ res[couple[0]] = decodeURIComponent(couple[1]);
+ });
+ return res;
+ }
+ let bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '3150ccb55da321',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '2'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '42dbe3a7168a6a',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ }
+ ];
+
+ it('should attach valid params to the tag', function () {
+ const request = spec.buildRequests([bidRequests[0]]);
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('u').that.is.a('string');
+ expect(payload).to.have.property('auids', '1');
+ expect(payload).to.have.property('r', '22edbae2733bf6');
+ });
+
+ it('auids must not be duplicated', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('u').that.is.a('string');
+ expect(payload).to.have.property('auids', '1,2');
+ expect(payload).to.have.property('r', '22edbae2733bf6');
+ });
+
+ it('if gdprConsent is present payload must have gdpr params', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '1');
+ });
+
+ it('if gdprApplies is false gdpr_applies must be 0', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '0');
+ });
+
+ it('if gdprApplies is undefined gdpr_applies must be 1', function () {
+ const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}});
+ expect(request.data).to.be.an('string');
+ const payload = parseRequest(request.data);
+ expect(payload).to.have.property('gdpr_consent', 'AAA');
+ expect(payload).to.have.property('gdpr_applies', '1');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const responses = [
+ {'bid': [{'price': 1.15, 'adm': 'test content 1
', 'auid': 1, 'h': 250, 'w': 300}], 'seat': '1'},
+ {'bid': [{'price': 0.5, 'adm': 'test content 2
', 'auid': 2, 'h': 90, 'w': 728}], 'seat': '1'},
+ {'bid': [{'price': 0, 'auid': 3, 'h': 250, 'w': 300}], 'seat': '1'},
+ {'bid': [{'price': 0, 'adm': 'test content 4
', 'h': 250, 'w': 300}], 'seat': '1'},
+ undefined,
+ {'bid': [], 'seat': '1'},
+ {'seat': '1'},
+ ];
+
+ it('should get correct bid response', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '659423fff799cb',
+ 'bidderRequestId': '5f2009617a7c0a',
+ 'auctionId': '1cbd2feafe5e8b',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const expectedResponse = [
+ {
+ 'requestId': '659423fff799cb',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ }
+ ];
+
+ const result = spec.interpretResponse({'body': {'seatbid': [responses[0]]}}, request);
+ expect(result).to.deep.equal(expectedResponse);
+ });
+
+ it('should get correct multi bid response', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d71a5b',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '2'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '4dff80cc4ee346',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '1'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '5703af74d0472a',
+ 'bidderRequestId': '2c2bb1972df9a',
+ 'auctionId': '1fa09aee5c8c99',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const expectedResponse = [
+ {
+ 'requestId': '300bfeb0d71a5b',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ },
+ {
+ 'requestId': '5703af74d0472a',
+ 'cpm': 1.15,
+ 'creativeId': 1,
+ 'dealId': undefined,
+ 'width': 300,
+ 'height': 250,
+ 'ad': 'test content 1
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ },
+ {
+ 'requestId': '4dff80cc4ee346',
+ 'cpm': 0.5,
+ 'creativeId': 2,
+ 'dealId': undefined,
+ 'width': 728,
+ 'height': 90,
+ 'ad': 'test content 2
',
+ 'bidderCode': 'grid',
+ 'currency': 'USD',
+ 'netRevenue': false,
+ 'ttl': 360,
+ }
+ ];
+
+ const result = spec.interpretResponse({'body': {'seatbid': [responses[0], responses[1]]}}, request);
+ expect(result).to.deep.equal(expectedResponse);
+ });
+
+ it('handles wrong and nobid responses', function () {
+ const bidRequests = [
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '3'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d7190gf',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '4'
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '300bfeb0d71321',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ },
+ {
+ 'bidder': 'grid',
+ 'params': {
+ 'uid': '5'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '300bfeb0d7183bb',
+ 'bidderRequestId': '2c2bb1972d23af',
+ 'auctionId': '1fa09aee5c84d34',
+ }
+ ];
+ const request = spec.buildRequests(bidRequests);
+ const result = spec.interpretResponse({'body': {'seatbid': responses.slice(2)}}, request);
+ expect(result.length).to.equal(0);
+ });
+ });
+});
diff --git a/test/spec/modules/justpremiumBidAdapter_spec.js b/test/spec/modules/justpremiumBidAdapter_spec.js
index 3c1048143d2..8167c29e5c2 100644
--- a/test/spec/modules/justpremiumBidAdapter_spec.js
+++ b/test/spec/modules/justpremiumBidAdapter_spec.js
@@ -1,7 +1,19 @@
import { expect } from 'chai'
-import { spec } from 'modules/justpremiumBidAdapter'
+import { spec, pixel } from 'modules/justpremiumBidAdapter'
describe('justpremium adapter', function () {
+ let sandbox;
+ let pixelStub;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+ pixelStub = sandbox.stub(pixel, 'fire');
+ });
+
+ afterEach(function() {
+ sandbox.restore();
+ });
+
let adUnits = [
{
adUnitCode: 'div-gpt-ad-1471513102552-1',
@@ -132,7 +144,7 @@ describe('justpremium adapter', function () {
})
describe('onTimeout', function () {
- it('onTimeout', (done) => {
+ it('onTimeout', function(done) {
spec.onTimeout([{
'bidId': '25cd3ec3fd6ed7',
'bidder': 'justpremium',
@@ -153,7 +165,9 @@ describe('justpremium adapter', function () {
'zone': 21521
}],
'timeout': 1
- }])
+ }]);
+
+ expect(pixelStub.calledOnce).to.equal(true);
done()
})
diff --git a/test/spec/modules/openxoutstreamBidAdapter_spec.js b/test/spec/modules/openxoutstreamBidAdapter_spec.js
index 59d56bee74b..9b189856e1a 100644
--- a/test/spec/modules/openxoutstreamBidAdapter_spec.js
+++ b/test/spec/modules/openxoutstreamBidAdapter_spec.js
@@ -44,28 +44,23 @@ describe('OpenXOutstreamAdapter', function () {
bannerBid.params = {delDomain: 'test-delivery-domain'}
});
- it('should return false when there is no ad unit id and size', function () {
+ it('should return false if there is no adunit id and sizes are defined', function () {
+ bannerBid.mediaTypes.banner.sizes = [720, 90];
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
- it('should return true if there is an adunit id ', function () {
+ it('should return true if there is delivery domain and unit', function () {
bannerBid.params.unit = '12345678';
expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
});
-
- it('should return true if there is no adunit id and sizes are defined', function () {
- bannerBid.mediaTypes.banner.sizes = [720, 90];
- expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
- });
-
- it('should return false if no sizes are defined ', function () {
+ it('should return false if there is unit but no delivery domain', function () {
+ bannerBid.params = {unit: '12345678'};
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
});
-
- it('should return false if sizes empty ', function () {
- bannerBid.mediaTypes.banner.sizes = [];
+ it('shoud return false if there is no delivery domain and no unit', function () {
+ bannerBid.params = {};
expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
- });
+ })
});
});
});
@@ -92,40 +87,45 @@ describe('OpenXOutstreamAdapter', function () {
expect(request[0].method).to.equal('GET');
});
- it('should send ad unit ids when any are defined', function () {
+ it('should send ad unit ids, height, and width when any are defined', function () {
const bidRequestsWithUnitIds = [{
'bidder': BIDDER,
'params': {
+ 'unit': '540141567',
+ 'height': '300',
+ 'width': '250',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
- 'sizes': [300, 250],
+ sizes: [300, 250],
mediaTypes: {
banner: {
- sizes: [[300, 250], [300, 600]]
+ sizes: [[728, 90]]
}
},
- 'bidId': 'test-bid-id-1',
- 'bidderRequestId': 'test-bid-request-1',
- 'auctionId': 'test-auction-1'
+ 'bidId': 'test-bid-id-2',
+ 'bidderRequestId': 'test-bid-request-2',
+ 'auctionId': 'test-auction-2'
}, {
'bidder': BIDDER,
'params': {
- 'unit': '540141567',
'delDomain': 'test-del-domain'
},
'adUnitCode': 'adunit-code',
+ 'sizes': [300, 250],
mediaTypes: {
banner: {
- sizes: [[728, 90]]
+ sizes: [[300, 250], [300, 600]]
}
},
- 'bidId': 'test-bid-id-2',
- 'bidderRequestId': 'test-bid-request-2',
- 'auctionId': 'test-auction-2'
+ 'bidId': 'test-bid-id-1',
+ 'bidderRequestId': 'test-bid-request-1',
+ 'auctionId': 'test-auction-1'
}];
const request = spec.buildRequests(bidRequestsWithUnitIds);
- expect(request[0].data.auid).to.equal(`${bidRequestsWithUnitIds[1].params.unit}`);
+ expect(request[0].data.auid).to.equal(`${bidRequestsWithUnitIds[0].params.unit}`);
+ expect(request[0].data.vht).to.equal(`${bidRequestsWithUnitIds[0].params.height}`);
+ expect(request[0].data.vwd).to.equal(`${bidRequestsWithUnitIds[0].params.width}`);
});
describe('interpretResponse', function () {
@@ -147,9 +147,9 @@ describe('OpenXOutstreamAdapter', function () {
};
serverRequest = {
payload: {
- bids: [{
+ bid: {
bidId: '2d36ac90d654af',
- }],
+ },
}
};
});
diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js
index f5a7602c7ab..e64294e87e2 100644
--- a/test/spec/modules/quantcastBidAdapter_spec.js
+++ b/test/spec/modules/quantcastBidAdapter_spec.js
@@ -1,5 +1,6 @@
import * as utils from 'src/utils';
import { expect } from 'chai';
+import { stub, sandbox } from 'sinon';
import {
QUANTCAST_DOMAIN,
QUANTCAST_TEST_DOMAIN,
@@ -12,6 +13,7 @@ import {
} from '../../../modules/quantcastBidAdapter';
import { newBidder } from '../../../src/adapters/bidderFactory';
import { parse } from 'src/url';
+import * as ajax from 'src/ajax';
describe('Quantcast adapter', function () {
const quantcastAdapter = newBidder(qcSpec);
@@ -211,4 +213,19 @@ describe('Quantcast adapter', function () {
expect(interpretedResponse.length).to.equal(0);
});
});
+
+ describe('`onTimeout`', function() {
+ it('makes a request to the notify endpoint', function() {
+ const sinonSandbox = sandbox.create();
+ const ajaxStub = sinonSandbox.stub(ajax, 'ajax').callsFake(function() {});
+ const timeoutData = {
+ bidder: 'quantcast'
+ };
+ qcSpec.onTimeout(timeoutData);
+ const expectedUrl = `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb_notify?type=timeout`;
+ ajaxStub.withArgs(expectedUrl, null, null).calledOnce.should.be.true;
+ ajaxStub.restore();
+ sinonSandbox.restore();
+ });
+ });
});
diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js
index f903f6e9c2d..0fc20171e0a 100644
--- a/test/spec/modules/rivrAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js
@@ -9,6 +9,9 @@ import {
dataLoaderForHandler,
pinHandlerToHTMLElement,
setAuctionAbjectPosition,
+ createNewAuctionObject,
+ concatAllUnits,
+ trackAuctionEnd,
} from 'modules/rivrAnalyticsAdapter';
import {expect} from 'chai';
import adaptermanager from 'src/adaptermanager';
@@ -20,9 +23,11 @@ const events = require('../../../src/events');
describe('RIVR Analytics adapter', () => {
const EXPIRING_QUEUE_TIMEOUT = 4000;
const EXPIRING_QUEUE_TIMEOUT_MOCK = 100;
- const PUBLISHER_ID_MOCK = 777;
+ const RVR_CLIENT_ID_MOCK = 'aCliendId';
+ const SITE_CATEGORIES_MOCK = ['cat1', 'cat2'];
const EMITTED_AUCTION_ID = 1;
const TRACKER_BASE_URL_MOCK = 'tracker.rivr.simplaex.com';
+ const UUID_REG_EXP = new RegExp('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', 'i');
let sandbox;
let ajaxStub;
let timer;
@@ -43,8 +48,9 @@ describe('RIVR Analytics adapter', () => {
adaptermanager.enableAnalytics({
provider: 'rivr',
options: {
- pubId: PUBLISHER_ID_MOCK,
- adUnits: [utils.deepClone(AD_UNITS_MOCK)]
+ clientID: RVR_CLIENT_ID_MOCK,
+ adUnits: [utils.deepClone(BANNER_AD_UNITS_MOCK)],
+ siteCategories: SITE_CATEGORIES_MOCK,
}
});
});
@@ -89,11 +95,15 @@ describe('RIVR Analytics adapter', () => {
timer.tick(50);
});
- it('enableAnalytics - should configure host and pubId in adapter context', () => {
+ it('enableAnalytics - should configure host and clientID in adapter context', () => {
// adaptermanager.enableAnalytics() is called in beforeEach. If only called here it doesn't seem to work.
expect(analyticsAdapter.context).to.have.property('host', TRACKER_BASE_URL_MOCK);
- expect(analyticsAdapter.context).to.have.property('pubId', PUBLISHER_ID_MOCK);
+ expect(analyticsAdapter.context).to.have.property('clientID', RVR_CLIENT_ID_MOCK);
+ });
+
+ it('enableAnalytics - should set a cookie containing a user id', () => {
+ expect(UUID_REG_EXP.test(analyticsAdapter.context.userId)).to.equal(true);
});
it('Firing AUCTION_INIT should set auction id of context when AUCTION_INIT event is fired', () => {
@@ -138,79 +148,6 @@ describe('RIVR Analytics adapter', () => {
expect(auctionObject3['modelVersion']).to.be.eql(null);
});
- it('Firing BID_REQUESTED it sets app and site publisher id in auction object', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
-
- const sitePubcid = analyticsAdapter.context.auctionObject.site.publisher.id;
- const appPubcid = analyticsAdapter.context.auctionObject.app.publisher.id;
- expect(sitePubcid).to.be.eql(PUBLISHER_ID_MOCK);
- expect(appPubcid).to.be.eql(PUBLISHER_ID_MOCK);
- });
-
- it('Firing BID_REQUESTED it adds bid request in bid requests array', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
-
- const requestEvent = analyticsAdapter.context.auctionObject.bidRequests;
- expect(requestEvent).to.have.length(1);
- expect(requestEvent[0]).to.be.eql({
- bidderCode: 'adapter',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
- bidderRequestId: '1a6fc81528d0f6',
- bids: [{
- bidder: 'adapter',
- params: {},
- adUnitCode: 'container-1',
- transactionId: 'de90df62-7fd0-4fbc-8787-92d133a7dc06',
- sizes: [[300, 250]],
- bidId: '208750227436c1',
- bidderRequestId: '1a6fc81528d0f6',
- auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f'
- }],
- auctionStart: 1509369418387,
- timeout: 3000,
- start: 1509369418389
- });
- });
-
- it('Firing BID_RESPONSE it inserts bid response object in auctionObject', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
-
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- const bidResponses = analyticsAdapter.context.auctionObject.bidResponses;
-
- expect(bidResponses).to.have.length(1);
- expect(bidResponses[0]).to.be.eql({
- timestamp: 1509369418832,
- status: 1,
- 'total_duration': 443,
- bidderId: null,
- 'bidder_name': 'adapter',
- cur: 'EU',
- seatbid: [
- {
- seat: null,
- bid: [
- {
- status: 2,
- 'clear_price': 0.015,
- attr: [],
- crid: 999,
- cid: null,
- id: null,
- adid: '208750227436c1',
- adomain: [],
- iurl: null
- }
- ]
- }
- ]
- });
- });
-
it('Firing AUCTION_END it sets auction time end to current time', () => {
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
@@ -223,54 +160,28 @@ describe('RIVR Analytics adapter', () => {
expect(endTime).to.be.eql(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
});
- it('Firing AUCTION_END when there are unresponded bid requests should insert then to bidResponses in auctionObject with null duration', () => {
+ it('Firing AUCTION_END populates impressions array in auction object', () => {
analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST2);
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST3);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
- const responses = analyticsAdapter.context.auctionObject.bidResponses;
- expect(responses.length).to.be.eql(2);
- expect(responses[0].total_duration).to.be.eql(null);
- expect(responses[1].total_duration).to.be.eql(null);
+ const impressions = analyticsAdapter.context.auctionObject.impressions;
+ expect(impressions.length).to.be.eql(3);
});
- it('Firing BID_WON when it happens after BID_RESPONSE should add won event as auction impression to imp array', () => {
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ it('Firing BID_WON should set to 1 the status of the corresponding bid', () => {
+ analyticsAdapter.context.auctionObject = utils.deepClone(AUCTION_OBJECT_AFTER_AUCTION_END_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
-
- const wonEvent = analyticsAdapter.context.auctionObject.imp;
-
- expect(wonEvent.length).to.be.eql(1);
- expect(wonEvent[0]).to.be.eql({
- tagid: 'container-1',
- displaymanager: null,
- displaymanagerver: null,
- secure: null,
- bidfloor: null,
- banner: {
- w: 300,
- h: 250,
- pos: null,
- expandable: [],
- api: []
- }
- });
- });
+ events.emit(CONSTANTS.EVENTS.BID_WON, BID_WON_MOCK);
- it('Firing BID_WON when it happens after BID_RESPONSE should change the status of winning bidResponse to 1', () => {
- const BID_STATUS_WON = 1;
- analyticsAdapter.context = utils.deepClone(CONTEXT_AFTER_AUCTION_INIT);
+ expect(analyticsAdapter.context.auctionObject.bidders.length).to.be.equal(3);
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+ expect(analyticsAdapter.context.auctionObject.bidders[0].bids[0].status).to.be.equal(0);
- const responseWhichIsWonAlso = analyticsAdapter.context.auctionObject.bidResponses[0];
+ expect(analyticsAdapter.context.auctionObject.bidders[1].bids[0].status).to.be.equal(0);
- expect(responseWhichIsWonAlso.seatbid[0].bid[0].status).to.be.eql(BID_STATUS_WON);
+ expect(analyticsAdapter.context.auctionObject.bidders[2].bids[0].status).to.be.equal(1);
+ expect(analyticsAdapter.context.auctionObject.bidders[2].bids[1].status).to.be.equal(0);
});
it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it sends the auction', () => {
@@ -284,31 +195,23 @@ describe('RIVR Analytics adapter', () => {
expect(ajaxStub.calledOnce).to.be.equal(true);
});
- it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it clears imp, bidResponses and bidRequests', () => {
+ it('when auction is initialized and authToken is defined and ExpiringQueue ttl expires, it resets auctionObject', () => {
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000});
analyticsAdapter.context.authToken = 'anAuthToken';
- events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST);
- events.emit(CONSTANTS.EVENTS.BID_RESPONSE, BID_RESPONSE_MOCK);
- events.emit(CONSTANTS.EVENTS.BID_WON, BID_RESPONSE_MOCK);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
- let impressions = analyticsAdapter.context.auctionObject.imp;
- let responses = analyticsAdapter.context.auctionObject.bidResponses;
- let requests = analyticsAdapter.context.auctionObject.bidRequests;
+ let impressions = analyticsAdapter.context.auctionObject.impressions;
- expect(impressions.length).to.be.eql(1);
- expect(responses.length).to.be.eql(1);
- expect(requests.length).to.be.eql(1);
+ expect(impressions.length).to.be.eql(3);
timer.tick(EXPIRING_QUEUE_TIMEOUT + 500);
- let impressionsAfterSend = analyticsAdapter.context.auctionObject.imp;
- let responsesAfterSend = analyticsAdapter.context.auctionObject.bidResponses;
- let requestsAfterSend = analyticsAdapter.context.auctionObject.bidRequests;
+ let impressionsAfterSend = analyticsAdapter.context.auctionObject.impressions;
+ let biddersAfterSend = analyticsAdapter.context.auctionObject.bidders;
expect(impressionsAfterSend.length).to.be.eql(0);
- expect(responsesAfterSend.length).to.be.eql(0);
- expect(requestsAfterSend.length).to.be.eql(0);
+ expect(biddersAfterSend.length).to.be.eql(0);
});
it('sendAuction(), when authToken is defined, it fires call clearing empty payload properties', () => {
@@ -547,7 +450,72 @@ describe('RIVR Analytics adapter', () => {
expect(analyticsAdapter.context.auctionObject.device.geo.lat).to.be.equal('aLatitude');
});
- const AD_UNITS_MOCK = [
+ it('createNewAuctionObject(), it creates a new auction object', () => {
+ const MILLIS_FROM_EPOCH_TO_NOW_MOCK = 123456;
+ timer.tick(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+
+ const result = createNewAuctionObject();
+
+ expect(result.device.deviceType).to.be.equal(2);
+ expect(result.publisher).to.be.equal(RVR_CLIENT_ID_MOCK);
+ expect(result.device.userAgent).to.be.equal(navigator.userAgent);
+ expect(result.timestamp).to.be.equal(MILLIS_FROM_EPOCH_TO_NOW_MOCK);
+ expect(result.site.domain.substring(0, 9)).to.be.equal('localhost');
+ expect(result.site.page).to.be.equal('/context.html');
+ expect(result.site.categories).to.be.equal(SITE_CATEGORIES_MOCK);
+ });
+
+ it('concatAllUnits(), returns a flattened array with all banner and video adunits', () => {
+ const allAdUnits = [BANNER_AD_UNITS_MOCK, VIDEO_AD_UNITS_MOCK];
+
+ const result = concatAllUnits(allAdUnits);
+
+ expect(result.length).to.be.eql(2);
+ expect(result[0].code).to.be.eql('banner-container1');
+ expect(result[1].code).to.be.eql('video');
+ });
+
+ it('trackAuctionEnd(), populates the bidders array from bidderRequests and bidsReceived', () => {
+ trackAuctionEnd(AUCTION_END_EVENT_WITH_BID_REQUESTS_AND_BID_RESPONSES_MOCK);
+
+ const result = analyticsAdapter.context.auctionObject.bidders;
+
+ expect(result.length).to.be.eql(3);
+
+ expect(result[0].id).to.be.eql('vuble');
+ expect(result[0].bids[0].price).to.be.eql(0);
+
+ expect(result[1].id).to.be.eql('vertamedia');
+ expect(result[1].bids[0].price).to.be.eql(0);
+
+ expect(result[2].id).to.be.eql('appnexus');
+ expect(result[2].bids[0].price).to.be.eql(0.5);
+ expect(result[2].bids[0].impId).to.be.eql('/19968336/header-bid-tag-0');
+ expect(result[2].bids[1].price).to.be.eql(0.7);
+ expect(result[2].bids[1].impId).to.be.eql('/19968336/header-bid-tag-1');
+ });
+
+ it('trackAuctionEnd(), populates the impressions array from adUnits', () => {
+ trackAuctionEnd(AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK);
+
+ const result = analyticsAdapter.context.auctionObject.impressions;
+
+ expect(result.length).to.be.eql(3);
+
+ expect(result[0].id).to.be.eql('/19968336/header-bid-tag-0');
+ expect(result[0].adType).to.be.eql('banner');
+
+ expect(result[1].id).to.be.eql('/19968336/header-bid-tag-1');
+ expect(result[1].adType).to.be.eql('banner');
+ expect(result[1].acceptedSizes).to.be.eql([{w: 728, h: 90}, {w: 970, h: 250}]);
+ expect(result[1].banner).to.be.eql({w: 300, h: 250});
+
+ expect(result[2].id).to.be.eql('video');
+ expect(result[2].adType).to.be.eql('video');
+ expect(result[2].acceptedSizes).to.be.eql([{w: 640, h: 360}, {w: 640, h: 480}]);
+ });
+
+ const BANNER_AD_UNITS_MOCK = [
{
code: 'banner-container1',
mediaTypes: {
@@ -573,6 +541,35 @@ describe('RIVR Analytics adapter', () => {
}
];
+ const VIDEO_AD_UNITS_MOCK = [
+ {
+ code: 'video',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ sizes: [[640, 360], [640, 480]]
+ }
+ },
+ bids: [
+ {
+ bidder: 'vuble',
+ params: {
+ env: 'net',
+ pubId: '18',
+ zoneId: '12345',
+ referrer: 'http://www.vuble.tv/', // optional
+ floorPrice: 5.00 // optional
+ }
+ },
+ {
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
+ }
+ }
+ ]
+ }];
+
const REQUEST = {
bidderCode: 'adapter',
auctionId: '5018eb39-f900-4370-b71e-3bb5b48d324f',
@@ -651,9 +648,56 @@ describe('RIVR Analytics adapter', () => {
size: '300x250'
};
+ const BID_WON_MOCK = {
+ bidderCode: 'appnexus',
+ width: 300,
+ height: 600,
+ statusMessage: 'Bid available',
+ adId: '63301dc59deb3b',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '63301dc59deb3b',
+ cpm: 0.5,
+ creativeId: 98493581,
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ ad: '...HTML CONTAINING THE AD...',
+ auctionId: '1825871c-b4c2-401a-b219-64549d412495',
+ responseTimestamp: 1540560447955,
+ requestTimestamp: 1540560447622,
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-0',
+ timeToRespond: 333,
+ pbLg: '0.50',
+ pbMg: '0.50',
+ pbHg: '0.50',
+ pbAg: '0.50',
+ pbDg: '0.50',
+ pbCg: '',
+ size: '300x600',
+ adserverTargeting: {
+ hb_bidder: 'appnexus',
+ hb_adid: '63301dc59deb3b',
+ hb_pb: '0.50',
+ hb_size: '300x600',
+ hb_source: 'client',
+ hb_format: 'banner'
+ },
+ status: 'rendered',
+ params: [
+ {
+ placementId: 13144370
+ }
+ ]
+ };
+
const CONTEXT_AFTER_AUCTION_INIT = {
host: TRACKER_BASE_URL_MOCK,
- pubId: PUBLISHER_ID_MOCK,
+ clientID: RVR_CLIENT_ID_MOCK,
queue: {
mockProp: 'mockValue'
},
@@ -699,4 +743,390 @@ describe('RIVR Analytics adapter', () => {
'ext.rivr.originalvalues': []
}
};
+
+ const AUCTION_END_EVENT_WITH_AD_UNITS_AND_BID_RESPONSES_MOCK = {
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ auctionStart: 1540560217395,
+ auctionEnd: 1540560217703,
+ auctionStatus: 'completed',
+ adUnits: [
+ {
+ code: '/19968336/header-bid-tag-0',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ }
+ },
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId: 'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
+ sizes: [
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ },
+ {
+ code: '/19968336/header-bid-tag-1',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 728,
+ 90
+ ],
+ [
+ 970,
+ 250
+ ]
+ ]
+ }
+ },
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId: '3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
+ sizes: [
+ [
+ 728,
+ 90
+ ],
+ [
+ 970,
+ 250
+ ]
+ ]
+ },
+ {
+ code: 'video',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ sizes: [
+ [
+ 640,
+ 360
+ ],
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ bids: [
+ {
+ bidder: 'vuble',
+ params: {
+ env: 'net',
+ pubId: '18',
+ zoneId: '12345',
+ referrer: 'http: //www.vuble.tv/',
+ floorPrice: 5
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ },
+ {
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ }
+ }
+ ],
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d'
+ }
+ ],
+ adUnitCodes: [
+ '/19968336/header-bid-tag-0',
+ '/19968336/header-bid-tag-1',
+ 'video'
+ ],
+ bidderRequests: [],
+ bidsReceived: [
+ {
+ bidderCode: 'appnexus',
+ width: 300,
+ height: 250,
+ statusMessage: 'Bid available',
+ adId: '6de82e80757293',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '6de82e80757293',
+ cpm: 0.5,
+ creativeId: 96846035,
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ ad: '...HTML CONTAINING THE AD...',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ responseTimestamp: 1540560217636,
+ requestTimestamp: 1540560217403,
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-1',
+ timeToRespond: 233,
+ pbLg: '0.50',
+ pbMg: '0.50',
+ pbHg: '0.50',
+ pbAg: '0.50',
+ pbDg: '0.50',
+ pbCg: '',
+ size: '728x90',
+ adserverTargeting: {
+ hb_bidder: 'appnexus',
+ hb_adid: '7e1a45d85bd57c',
+ hb_pb: '0.50',
+ hb_size: '728x90',
+ hb_source: 'client',
+ hb_format: 'banner'
+ }
+ }
+ ],
+ winningBids: [],
+ timeout: 3000
+ };
+
+ const AUCTION_OBJECT_AFTER_AUCTION_END_MOCK = {
+ bidders: [
+ {
+ id: 'vuble',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: 'video',
+ price: 0,
+ status: 0
+ }
+ ]
+ },
+ {
+ id: 'vertamedia',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: 'video',
+ price: 0,
+ status: 0
+ }
+ ]
+ },
+ {
+ id: 'appnexus',
+ bids: [
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: '/19968336/header-bid-tag-0',
+ price: 0.5,
+ status: 0
+ },
+ {
+ adomain: [
+ ''
+ ],
+ clearPrice: 0,
+ impId: '/19968336/header-bid-tag-1',
+ price: 0.7,
+ status: 0
+ }
+ ]
+ }
+ ],
+ impressions: []
+ };
+
+ const AUCTION_END_EVENT_WITH_BID_REQUESTS_AND_BID_RESPONSES_MOCK = {
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ auctionStart: 1540560217395,
+ auctionEnd: 1540560217703,
+ auctionStatus: 'completed',
+ adUnits: [],
+ adUnitCodes: [
+ '/19968336/header-bid-tag-0',
+ '/19968336/header-bid-tag-1',
+ 'video'
+ ],
+ bidderRequests: [
+ {
+ bidderCode: 'vuble',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '1bb11e055665bc',
+ bids: [
+ {
+ bidder: 'vuble',
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: 'video',
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d',
+ bidId: '2859b890da7418',
+ bidderRequestId: '1bb11e055665bc',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ refererInfo: {
+ referer: 'http: //localhost: 8080/',
+ reachedTop: true,
+ numIframes: 0,
+ stack: [
+ 'http://localhost:8080/'
+ ]
+ },
+ start: 1540560217401,
+ doneCbCallCount: 0
+ },
+ {
+ bidderCode: 'vertamedia',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '3c2cbf7f1466cb',
+ bids: [
+ {
+ bidder: 'vertamedia',
+ params: {
+ aid: 331133
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: 'video',
+ transactionId: 'df11a105-4eef-4ceb-bbc3-a49224f7c49d',
+ bidId: '45b3ad5c2dc794',
+ bidderRequestId: '3c2cbf7f1466cb',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ start: 1540560217401
+ },
+ {
+ bidderCode: 'appnexus',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidderRequestId: '5312eef4418cd7',
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: '/19968336/header-bid-tag-0',
+ transactionId: 'aee9bf8d-6d8f-425b-a42a-52c875371ebc',
+ bidId: '6de82e80757293',
+ bidderRequestId: '5312eef4418cd7',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ },
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 13144370
+ },
+ crumbs: {
+ pubcid: '87eb6b0e-e1a8-42a9-b58d-e93a382e2d9b'
+ },
+ adUnitCode: '/19968336/header-bid-tag-1',
+ transactionId: '3d5f0f89-e9cd-4714-b314-3f0fb7fcf8e3',
+ bidId: '7e1a45d85bd57c',
+ bidderRequestId: '5312eef4418cd7',
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ src: 'client',
+ bidRequestsCount: 1
+ }
+ ],
+ auctionStart: 1540560217395,
+ timeout: 3000,
+ start: 1540560217403,
+ doneCbCallCount: 0
+ }
+ ],
+ bidsReceived: [
+ {
+ bidderCode: 'appnexus',
+ adId: '6de82e80757293',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '6de82e80757293',
+ cpm: 0.5,
+ creativeId: 96846035,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-0',
+ },
+ {
+ bidderCode: 'appnexus',
+ adId: '7e1a45d85bd57c',
+ mediaType: 'banner',
+ source: 'client',
+ requestId: '7e1a45d85bd57c',
+ cpm: 0.7,
+ creativeId: 96846035,
+ appnexus: {
+ buyerMemberId: 9325
+ },
+ auctionId: 'f6c1d093-14a3-4ade-bc7d-1de37e7cbdb2',
+ bidder: 'appnexus',
+ adUnitCode: '/19968336/header-bid-tag-1',
+ }
+ ],
+ winningBids: [],
+ timeout: 3000
+ };
});
diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js
index 3c1d81a86c9..bd341465ab9 100644
--- a/test/spec/modules/rtbhouseBidAdapter_spec.js
+++ b/test/spec/modules/rtbhouseBidAdapter_spec.js
@@ -52,17 +52,26 @@ describe('RTBHouseAdapter', () => {
'sizes': [[300, 250], [300, 600]],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
- 'auctionId': '1d1a030790a475'
+ 'auctionId': '1d1a030790a475',
+ 'transactionId': 'example-transaction-id',
}
];
+ const bidderRequest = {
+ 'refererInfo': {
+ 'numIframes': 0,
+ 'reachedTop': true,
+ 'referer': 'http://example.com',
+ 'stack': ['http://example.com']
+ }
+ };
it('should build test param into the request', () => {
- let builtTestRequest = spec.buildRequests(bidRequests).data;
+ let builtTestRequest = spec.buildRequests(bidRequests, bidderRequest).data;
expect(JSON.parse(builtTestRequest).test).to.equal(1);
});
it('should build valid OpenRTB banner object', () => {
- const request = JSON.parse(spec.buildRequests((bidRequests)).data);
+ const request = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data);
const imp = request.imp[0];
expect(imp.banner).to.deep.equal({
w: 300,
@@ -80,7 +89,7 @@ describe('RTBHouseAdapter', () => {
it('sends bid request to ENDPOINT via POST', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
expect(request.url).to.equal('https://prebid-eu.creativecdn.com/bidder/prebid/bids');
expect(request.method).to.equal('POST');
});
@@ -88,7 +97,7 @@ describe('RTBHouseAdapter', () => {
it('should not populate GDPR if for non-EEA users', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
let data = JSON.parse(request.data);
expect(data).to.not.have.property('regs');
expect(data).to.not.have.property('user');
@@ -97,12 +106,15 @@ describe('RTBHouseAdapter', () => {
it('should populate GDPR and consent string if available for EEA users', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest, {
- gdprConsent: {
- gdprApplies: true,
- consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='
- }
- });
+ const request = spec.buildRequests(
+ bidRequest,
+ Object.assign({}, bidderRequest, {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='
+ }
+ })
+ );
let data = JSON.parse(request.data);
expect(data.regs.ext.gdpr).to.equal(1);
expect(data.user.ext.consent).to.equal('BOJ8RZsOJ8RZsABAB8AAAAAZ-A');
@@ -111,7 +123,14 @@ describe('RTBHouseAdapter', () => {
it('should populate GDPR and empty consent string if available for EEA users without consent string but with consent', function () {
let bidRequest = Object.assign([], bidRequests);
delete bidRequest[0].params.test;
- const request = spec.buildRequests(bidRequest, {gdprConsent: {gdprApplies: true}});
+ const request = spec.buildRequests(
+ bidRequest,
+ Object.assign({}, bidderRequest, {
+ gdprConsent: {
+ gdprApplies: true
+ }
+ })
+ );
let data = JSON.parse(request.data);
expect(data.regs.ext.gdpr).to.equal(1);
expect(data.user.ext.consent).to.equal('');
@@ -119,11 +138,26 @@ describe('RTBHouseAdapter', () => {
it('should include banner imp in request', () => {
const bidRequest = Object.assign([], bidRequests);
- const request = spec.buildRequests(bidRequest);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
const data = JSON.parse(request.data);
expect(data.imp[0].banner).to.not.be.empty;
});
+ it('should include source.tid in request', () => {
+ const bidRequest = Object.assign([], bidRequests);
+ const request = spec.buildRequests(bidRequest, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.source.tid).to.equal('example-transaction-id');
+ });
+
+ it('should include bidfloor in request if available', () => {
+ const bidRequest = Object.assign([], bidRequests);
+ bidRequest[0].params.bidfloor = 0.01;
+ const request = spec.buildRequests(bidRequest, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.imp[0].bidfloor).to.equal(0.01)
+ });
+
describe('native imp', () => {
function basicRequest(extension) {
return Object.assign({
@@ -139,7 +173,8 @@ describe('RTBHouseAdapter', () => {
}
function buildImp(request) {
- return JSON.parse(spec.buildRequests([request]).data).imp[0];
+ const resultRequest = spec.buildRequests([request], bidderRequest);
+ return JSON.parse(resultRequest.data).imp[0];
}
it('should extract native params when single mediaType', () => {
diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js
index fa64513730a..97737675325 100644
--- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js
+++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js
@@ -106,9 +106,59 @@ const MOCK = {
[BID2.adUnitCode]: BID2.adserverTargeting
},
AUCTION_INIT: {
- 'timestamp': 1519767010567,
'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
- 'timeout': 3000
+ 'timestamp': 1519767010567,
+ 'auctionStatus': 'inProgress',
+ 'adUnits': [ {
+ 'code': '/19968336/header-bid-tag1',
+ 'sizes': [[640, 480]],
+ 'bids': [ {
+ 'bidder': 'rubicon',
+ 'params': {
+ 'accountId': 1001, 'siteId': 113932, 'zoneId': 535512
+ }
+ } ],
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014'
+ }
+ ],
+ 'adUnitCodes': ['/19968336/header-bid-tag1'],
+ 'bidderRequests': [ {
+ 'bidderCode': 'rubicon',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'bidderRequestId': '1be65d7958826a',
+ 'bids': [ {
+ 'bidder': 'rubicon',
+ 'params': {
+ 'accountId': 1001, 'siteId': 113932, 'zoneId': 535512
+ },
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[640, 480]]
+ }
+ },
+ 'adUnitCode': '/19968336/header-bid-tag1',
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014',
+ 'sizes': [[640, 480]],
+ 'bidId': '2ecff0db240757',
+ 'bidderRequestId': '1be65d7958826a',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'src': 'client',
+ 'bidRequestsCount': 1
+ }
+ ],
+ 'auctionStart': 1519767010567,
+ 'timeout': 3000,
+ 'refererInfo': {
+ 'referer': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html']
+ }
+ }
+ ],
+ 'bidsReceived': [],
+ 'winningBids': [],
+ 'timeout': 3000,
+ 'config': {
+ 'accountId': 1001, 'endpoint': '//localhost:9999/event'
+ }
},
BID_REQUESTED: {
'bidder': 'rubicon',
diff --git a/test/spec/modules/undertoneBidAdapter_spec.js b/test/spec/modules/undertoneBidAdapter_spec.js
index 4b816d851d9..400e86567ea 100644
--- a/test/spec/modules/undertoneBidAdapter_spec.js
+++ b/test/spec/modules/undertoneBidAdapter_spec.js
@@ -44,6 +44,12 @@ const bidReq = [{
auctionId: '6c22f5a5-59df-4dc6-b92c-f433bcf0a874'
}];
+const bidderReq = {
+ refererInfo: {
+ referer: 'http://prebid.org/dev-docs/bidder-adaptor.html'
+ }
+};
+
const validBidRes = {
ad: 'Hello
',
publisherId: 12345,
@@ -98,14 +104,16 @@ describe('Undertone Adapter', function () {
});
describe('build request', function () {
it('should send request to correct url via POST', function () {
- const request = spec.buildRequests(bidReq);
- const domain = null;
+ const request = spec.buildRequests(bidReq, bidderReq);
+ const domainStart = bidderReq.refererInfo.referer.indexOf('//');
+ const domainEnd = bidderReq.refererInfo.referer.indexOf('/', domainStart + 2);
+ const domain = bidderReq.refererInfo.referer.substring(domainStart + 2, domainEnd);
const REQ_URL = `${URL}?pid=${bidReq[0].params.publisherId}&domain=${domain}`;
expect(request.url).to.equal(REQ_URL);
expect(request.method).to.equal('POST');
});
it('should have all relevant fields', function () {
- const request = spec.buildRequests(bidReq);
+ const request = spec.buildRequests(bidReq, bidderReq);
const bid1 = JSON.parse(request.data)['x-ut-hb-params'][0];
expect(bid1.bidRequestId).to.equal('263be71e91dd9d');
expect(bid1.sizes.length).to.equal(2);
@@ -150,4 +158,27 @@ describe('Undertone Adapter', function () {
expect(spec.interpretResponse({ body: bidResArray }).length).to.equal(1);
});
});
+
+ describe('getUserSyncs', () => {
+ it('verifies gdpr consent checked', () => {
+ const options = ({ iframeEnabled: true, pixelEnabled: true });
+ expect(spec.getUserSyncs(options, {}, { gdprApplies: true }).length).to.equal(0);
+ });
+
+ it('Verifies sync iframe option', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true });
+ expect(result).to.have.lengthOf(1);
+ expect(result[0].type).to.equal('iframe');
+ expect(result[0].url).to.equal('//cdn.undertone.com/js/usersync.html');
+ });
+
+ it('Verifies sync image option', function () {
+ const result = spec.getUserSyncs({ pixelEnabled: true });
+ expect(result).to.have.lengthOf(2);
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=1&of=2');
+ expect(result[1].type).to.equal('image');
+ expect(result[1].url).to.equal('//usr.undertone.com/userPixel/syncOne?id=2&of=2');
+ });
+ });
});
diff --git a/test/spec/modules/uolBidAdapter_spec.js b/test/spec/modules/uolBidAdapter_spec.js
index 1733afc91f9..e9341772e7d 100644
--- a/test/spec/modules/uolBidAdapter_spec.js
+++ b/test/spec/modules/uolBidAdapter_spec.js
@@ -1,11 +1,20 @@
import { expect } from 'chai';
import { spec } from 'modules/uolBidAdapter';
-import { newBidder } from 'src/adapters/bidderFactory';
const ENDPOINT = 'https://prebid.adilligo.com/v1/prebid.json';
describe('UOL Bid Adapter', function () {
- const adapter = newBidder(spec);
+ let sandbox;
+ let queryStub;
+ let getCurrentPositionStub;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+ });
+
+ afterEach(function() {
+ sandbox.restore();
+ });
describe('isBidRequestValid', function () {
let bid = {
@@ -88,31 +97,6 @@ describe('UOL Bid Adapter', function () {
});
describe('buildRequests', function () {
- let queryPermission;
- let cleanup = function() {
- navigator.permissions.query = queryPermission;
- };
- let grantTriangulation = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = function(data) {
- return new Promise((resolve, reject) => {
- resolve({state: 'granted'});
- });
- }
- };
- let denyTriangulation = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = function(data) {
- return new Promise((resolve, reject) => {
- resolve({state: 'prompt'});
- });
- }
- };
- let removeQuerySupport = function() {
- queryPermission = navigator.permissions.query;
- navigator.permissions.query = undefined;
- }
-
let bidRequests = [
{
'bidder': 'uol',
@@ -173,31 +157,42 @@ describe('UOL Bid Adapter', function () {
describe('buildRequest geolocation param', function () { // shall only be tested if browser engine supports geolocation and permissions API.
let geolocation = { lat: 4, long: 3, timestamp: 123121451 };
- it('should contain user coordinates if (i) DNT is off; (ii) browser supports implementation; (iii) localStorage contains geolocation history', function () {
+ beforeEach(function() {
+ getCurrentPositionStub = sandbox.stub(navigator.geolocation, 'getCurrentPosition');
+ queryStub = sandbox.stub(navigator.permissions, 'query');
+ });
+
+ it('should not contain user coordinates if browser doesnt support permission query', function () {
localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
- grantTriangulation();
+ navigator.permissions.query = undefined;
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
- expect(payload.geolocation).to.exist.and.not.be.empty;
- cleanup();
+ expect(payload.geolocation).to.not.exist;
})
- it('should not contain user coordinates if localStorage is empty', function () {
- localStorage.removeItem('uolLocationTracker');
- denyTriangulation();
+ it('should contain user coordinates if (i) DNT is off; (ii) browser supports implementation; (iii) localStorage contains geolocation history', function (done) {
+ localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
+ queryStub.callsFake(function() {
+ return new Promise((resolve, reject) => {
+ resolve({state: 'granted'});
+ });
+ });
+ getCurrentPositionStub.callsFake(() => done());
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
- expect(payload.geolocation).to.not.exist;
- cleanup();
+ expect(payload.geolocation).to.exist.and.not.be.empty;
})
- it('should not contain user coordinates if browser doesnt support permission query', function () {
- localStorage.setItem('uolLocationTracker', JSON.stringify(geolocation));
- removeQuerySupport();
+ it('should not contain user coordinates if localStorage is empty', function () {
+ localStorage.removeItem('uolLocationTracker');
+ queryStub.callsFake(function() {
+ return new Promise((resolve, reject) => {
+ resolve({state: 'prompt'});
+ });
+ });
const requestObject = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(requestObject.data);
expect(payload.geolocation).to.not.exist;
- cleanup();
})
})
}
diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js
index b717ef52709..19756b86bc1 100644
--- a/test/spec/modules/yieldoneBidAdapter_spec.js
+++ b/test/spec/modules/yieldoneBidAdapter_spec.js
@@ -3,6 +3,7 @@ import { spec } from 'modules/yieldoneBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';
const ENDPOINT = '//y.one.impact-ad.jp/h_bid';
+const USER_SYNC_URL = '//y.one.impact-ad.jp/push_sync';
describe('yieldoneBidAdapter', function() {
const adapter = newBidder(spec);
@@ -11,12 +12,10 @@ describe('yieldoneBidAdapter', function() {
let bid = {
'bidder': 'yieldone',
'params': {
- placementId: '44082'
+ placementId: '36891'
},
'adUnitCode': 'adunit-code',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250], [336, 280]],
'bidId': '23beaa6af6cdde',
'bidderRequestId': '19c0c1efdf37e7',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -43,12 +42,10 @@ describe('yieldoneBidAdapter', function() {
{
'bidder': 'yieldone',
'params': {
- placementId: '44082'
+ placementId: '36891'
},
'adUnitCode': 'adunit-code1',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250], [336, 280]],
'bidId': '23beaa6af6cdde',
'bidderRequestId': '19c0c1efdf37e7',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -56,12 +53,10 @@ describe('yieldoneBidAdapter', function() {
{
'bidder': 'yieldone',
'params': {
- placementId: '44337'
+ placementId: '47919'
},
'adUnitCode': 'adunit-code2',
- 'sizes': [
- [300, 250]
- ],
+ 'sizes': [[300, 250]],
'bidId': '382091349b149f"',
'bidderRequestId': '"1f9c98192de251"',
'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1',
@@ -79,18 +74,31 @@ describe('yieldoneBidAdapter', function() {
expect(request[0].url).to.equal(ENDPOINT);
expect(request[1].url).to.equal(ENDPOINT);
});
+
+ it('parameter sz has more than one size on banner requests', function () {
+ expect(request[0].data.sz).to.equal('300x250,336x280');
+ expect(request[1].data.sz).to.equal('300x250');
+ });
+
+ it('width and height should be set as separate parameters on outstream requests', function () {
+ const bidRequest = Object.assign({}, bidRequests[0]);
+ bidRequest.mediaTypes = {};
+ bidRequest.mediaTypes.video = {context: 'outstream'};
+ const request = spec.buildRequests([bidRequest]);
+ expect(request[0].data.w).to.equal('300');
+ expect(request[0].data.h).to.equal('250');
+ });
});
describe('interpretResponse', function () {
- let bidRequest = [
+ let bidRequestBanner = [
{
'method': 'GET',
'url': '//y.one.impact-ad.jp/h_bid',
'data': {
'v': 'hb1',
- 'p': '44082',
- 'w': '300',
- 'h': '250',
+ 'p': '36891',
+ 'sz': '300x250,336x280',
'cb': 12892917383,
'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836',
'uid': '23beaa6af6cdde',
@@ -99,34 +107,89 @@ describe('yieldoneBidAdapter', function() {
}
];
- let serverResponse = {
+ let serverResponseBanner = {
body: {
'adTag': '',
+ 'uid': '23beaa6af6cdde',
+ 'height': 250,
+ 'width': 300,
'cpm': 0.0536616,
'crid': '2494768',
+ 'currency': 'JPY',
'statusMessage': 'Bid available',
- 'uid': '23beaa6af6cdde',
- 'width': 300,
- 'height': 250
+ 'dealId': 'P1-FIX-7800-DSP-MON'
}
};
- it('should get the correct bid response', function () {
+ it('should get the correct bid response for banner', function () {
let expectedResponse = [{
'requestId': '23beaa6af6cdde',
'cpm': 53.6616,
'width': 300,
'height': 250,
'creativeId': '2494768',
- 'dealId': '',
+ 'dealId': 'P1-FIX-7800-DSP-MON',
'currency': 'JPY',
'netRevenue': true,
'ttl': 3000,
'referrer': '',
+ 'mediaType': 'banner',
'ad': ''
}];
- let result = spec.interpretResponse(serverResponse, bidRequest[0]);
- expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse));
+ let result = spec.interpretResponse(serverResponseBanner, bidRequestBanner[0]);
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0]));
+ expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType);
+ });
+
+ let serverResponseVideo = {
+ body: {
+ 'uid': '23beaa6af6cdde',
+ 'height': 360,
+ 'width': 640,
+ 'cpm': 0.0536616,
+ 'dealId': 'P1-FIX-766-DSP-MON',
+ 'crid': '2494768',
+ 'currency': 'JPY',
+ 'statusMessage': 'Bid available',
+ 'adm': ''
+ }
+ };
+
+ let bidRequestVideo = [
+ {
+ 'method': 'GET',
+ 'url': '//y.one.impact-ad.jp/h_bid',
+ 'data': {
+ 'v': 'hb1',
+ 'p': '41993',
+ 'w': '640',
+ 'h': '360',
+ 'cb': 12892917383,
+ 'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836',
+ 'uid': '23beaa6af6cdde',
+ 't': 'i'
+ }
+ }
+ ];
+
+ it('should get the correct bid response for video', function () {
+ let expectedResponse = [{
+ 'requestId': '23beaa6af6cdde',
+ 'cpm': 53.6616,
+ 'width': 640,
+ 'height': 360,
+ 'creativeId': '2494768',
+ 'dealId': 'P1-FIX-7800-DSP-MON',
+ 'currency': 'JPY',
+ 'netRevenue': true,
+ 'ttl': 3000,
+ 'referrer': '',
+ 'mediaType': 'video',
+ 'vastXml': ''
+ }];
+ let result = spec.interpretResponse(serverResponseVideo, bidRequestVideo[0]);
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0]));
+ expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType);
});
it('handles empty bid response', function () {
@@ -140,14 +203,12 @@ describe('yieldoneBidAdapter', function() {
'cpm': 0
}
};
- let result = spec.interpretResponse(response, bidRequest[0]);
+ let result = spec.interpretResponse(response, bidRequestBanner[0]);
expect(result.length).to.equal(0);
});
});
describe('getUserSyncs', function () {
- const userSyncUrl = '//y.one.impact-ad.jp/push_sync';
-
it('handles empty sync options', function () {
expect(spec.getUserSyncs({})).to.be.empty;
});
@@ -156,7 +217,7 @@ describe('yieldoneBidAdapter', function() {
expect(spec.getUserSyncs({
'iframeEnabled': true
})).to.deep.equal([{
- type: 'iframe', url: userSyncUrl
+ type: 'iframe', url: USER_SYNC_URL
}]);
});
});
diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js
index 91b96cac281..68653808c06 100644
--- a/test/spec/native_spec.js
+++ b/test/spec/native_spec.js
@@ -16,6 +16,19 @@ const bid = {
}
};
+const bidWithUndefinedFields = {
+ native: {
+ title: 'Native Creative',
+ body: undefined,
+ cta: undefined,
+ sponsoredBy: 'AppNexus',
+ clickUrl: 'https://www.link.example',
+ clickTrackers: ['https://tracker.example'],
+ impressionTrackers: ['https://impression.example'],
+ javascriptTrackers: ''
+ }
+};
+
describe('native.js', function () {
let triggerPixelStub;
let insertHtmlIntoIframeStub;
@@ -37,6 +50,16 @@ describe('native.js', function () {
expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal(bid.native.clickUrl);
});
+ it('should only include native targeting keys with values', function () {
+ const targeting = getNativeTargeting(bidWithUndefinedFields);
+
+ expect(Object.keys(targeting)).to.deep.equal([
+ CONSTANTS.NATIVE_KEYS.title,
+ CONSTANTS.NATIVE_KEYS.sponsoredBy,
+ CONSTANTS.NATIVE_KEYS.clickUrl
+ ]);
+ });
+
it('fires impression trackers', function () {
fireNativeTrackers({}, bid);
sinon.assert.calledOnce(triggerPixelStub);
diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js
index 9910645be09..427ceeca74c 100644
--- a/test/spec/unit/core/targeting_spec.js
+++ b/test/spec/unit/core/targeting_spec.js
@@ -99,42 +99,68 @@ const bid3 = {
};
describe('targeting tests', function () {
+ let sandbox;
+ let enableSendAllBids = false;
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+
+ let origGetConfig = config.getConfig;
+ sandbox.stub(config, 'getConfig').callsFake(function (key) {
+ if (key === 'enableSendAllBids') {
+ return enableSendAllBids;
+ }
+ return origGetConfig.apply(config, arguments);
+ });
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
describe('getAllTargeting', function () {
let amBidsReceivedStub;
let amGetAdUnitsStub;
let bidExpiryStub;
+ let bidsReceived;
beforeEach(function () {
- $$PREBID_GLOBAL$$._sendAllBids = false;
- amBidsReceivedStub = sinon.stub(auctionManager, 'getBidsReceived').callsFake(function() {
- return [bid1, bid2, bid3];
+ bidsReceived = [bid1, bid2, bid3];
+
+ amBidsReceivedStub = sandbox.stub(auctionManager, 'getBidsReceived').callsFake(function() {
+ return bidsReceived;
});
- amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
+ amGetAdUnitsStub = sandbox.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
return ['/123456/header-bid-tag-0'];
});
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
- });
-
- afterEach(function () {
- auctionManager.getBidsReceived.restore();
- auctionManager.getAdUnitCodes.restore();
- targetingModule.isBidNotExpired.restore();
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
});
describe('when hb_deal is present in bid.adserverTargeting', function () {
+ let bid4;
+
+ beforeEach(function() {
+ bid4 = utils.deepClone(bid1);
+ bid4.adserverTargeting['hb_bidder'] = bid4.bidder = bid4.bidderCode = 'appnexus';
+ bid4.cpm = 0;
+ enableSendAllBids = true;
+
+ bidsReceived.push(bid4);
+ });
+
it('returns targeting with both hb_deal and hb_deal_{bidder_code}', function () {
const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']);
// We should add both keys rather than one or the other
- expect(targeting['/123456/header-bid-tag-0']).to.contain.keys('hb_deal', `hb_deal_${bid1.bidderCode}`);
+ expect(targeting['/123456/header-bid-tag-0']).to.contain.keys('hb_deal', `hb_deal_${bid1.bidderCode}`, `hb_deal_${bid4.bidderCode}`);
// We should assign both keys the same value
expect(targeting['/123456/header-bid-tag-0']['hb_deal']).to.deep.equal(targeting['/123456/header-bid-tag-0'][`hb_deal_${bid1.bidderCode}`]);
});
});
- it('selects the top bid when _sendAllBids true', function () {
- config.setConfig({ enableSendAllBids: true });
+ it('selects the top bid when enableSendAllBids true', function () {
+ enableSendAllBids = true;
let targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']);
// we should only get the targeting data for the one requested adunit
@@ -155,14 +181,13 @@ describe('targeting tests', function () {
let bidExpiryStub;
beforeEach(function () {
- $$PREBID_GLOBAL$$._sendAllBids = false;
- amBidsReceivedStub = sinon.stub(auctionManager, 'getBidsReceived').callsFake(function() {
+ amBidsReceivedStub = sandbox.stub(auctionManager, 'getBidsReceived').callsFake(function() {
return [];
});
- amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
+ amGetAdUnitsStub = sandbox.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
return ['/123456/header-bid-tag-0'];
});
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
});
afterEach(function () {
@@ -184,13 +209,8 @@ describe('targeting tests', function () {
let bidExpiryStub;
let auctionManagerStub;
beforeEach(function () {
- bidExpiryStub = sinon.stub(targetingModule, 'isBidNotExpired').returns(true);
- auctionManagerStub = sinon.stub(auctionManager, 'getBidsReceived');
- });
-
- afterEach(function () {
- bidExpiryStub.restore();
- auctionManagerStub.restore();
+ bidExpiryStub = sandbox.stub(targetingModule, 'isBidNotExpired').returns(true);
+ auctionManagerStub = sandbox.stub(auctionManager, 'getBidsReceived');
});
it('should use bids from pool to get Winning Bid', function () {
@@ -248,14 +268,10 @@ describe('targeting tests', function () {
let auctionManagerStub;
let timestampStub;
beforeEach(function () {
- auctionManagerStub = sinon.stub(auctionManager, 'getBidsReceived');
- timestampStub = sinon.stub(utils, 'timestamp');
+ auctionManagerStub = sandbox.stub(auctionManager, 'getBidsReceived');
+ timestampStub = sandbox.stub(utils, 'timestamp');
});
- afterEach(function () {
- auctionManagerStub.restore();
- timestampStub.restore();
- });
it('should not include expired bids in the auction', function () {
timestampStub.returns(200000);
// Pool is having 4 bids from 2 auctions. All the bids are expired and only bid #3 is passing the bidExpiry check.