diff --git a/modules/cleanmedianetBidAdapter.js b/modules/cleanmedianetBidAdapter.js
index ba72eec3d95..46253d7af69 100644
--- a/modules/cleanmedianetBidAdapter.js
+++ b/modules/cleanmedianetBidAdapter.js
@@ -1,13 +1,34 @@
-import {deepAccess, getDNT, inIframe, isArray, isNumber, logError, logWarn} from '../src/utils.js';
+import {
+ deepAccess,
+ deepSetValue,
+ getDNT,
+ inIframe,
+ isArray,
+ isFn,
+ isNumber,
+ isPlainObject,
+ isStr,
+ logError,
+ logWarn
+} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {Renderer} from '../src/Renderer.js';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
import {includes} from '../src/polyfill.js';
+const ENDPOINTS = {
+ 'cleanmedianet': 'https://bidder.cleanmediaads.com'
+};
+
+const DEFAULT_TTL = 360;
+
export const helper = {
- getTopWindowDomain: function (url) {
- const domainStart = url.indexOf('://') + '://'.length;
- return url.substring(domainStart, url.indexOf('/', domainStart) < 0 ? url.length : url.indexOf('/', domainStart));
+ getTopFrame: function () {
+ try {
+ return window.top === window ? 1 : 0;
+ } catch (e) {
+ }
+ return 0;
},
startsWith: function (str, search) {
return str.substr(0, search.length) === search;
@@ -23,53 +44,50 @@ export const helper = {
}
}
return BANNER;
+ },
+ getBidFloor(bid) {
+ if (!isFn(bid.getFloor)) {
+ return bid.params.bidfloor ? bid.params.bidfloor : null;
+ }
+
+ let bidFloor = bid.getFloor({
+ mediaType: '*',
+ size: '*',
+ currency: 'USD'
+ });
+
+ if (isPlainObject(bidFloor) && !isNaN(bidFloor.floor) && bidFloor.currency === 'USD') {
+ return bidFloor.floor;
+ }
+
+ return null;
}
};
export const spec = {
code: 'cleanmedianet',
aliases: [],
- supportedMediaTypes: [BANNER, VIDEO],
+ supportedMediaTypes: ['banner', 'video'],
isBidRequestValid: function (bid) {
- return (
- !!bid.params.supplyPartnerId &&
- typeof bid.params.supplyPartnerId === 'string' &&
- (typeof bid.params.bidfloor === 'undefined' ||
- typeof bid.params.bidfloor === 'number') &&
- (typeof bid.params['adpos'] === 'undefined' ||
- typeof bid.params['adpos'] === 'number') &&
- (typeof bid.params['protocols'] === 'undefined' ||
- Array.isArray(bid.params['protocols'])) &&
- (typeof bid.params.instl === 'undefined' ||
- bid.params.instl === 0 ||
- bid.params.instl === 1)
- );
+ return !!bid.params.supplyPartnerId && isStr(bid.params.supplyPartnerId) &&
+ (!bid.params['rtbEndpoint'] || isStr(bid.params['rtbEndpoint'])) &&
+ (!bid.params.bidfloor || isNumber(bid.params.bidfloor)) &&
+ (!bid.params['adpos'] || isNumber(bid.params['adpos'])) &&
+ (!bid.params['protocols'] || Array.isArray(bid.params['protocols'])) &&
+ (!bid.params.instl || bid.params.instl === 0 || bid.params.instl === 1);
},
buildRequests: function (validBidRequests, bidderRequest) {
return validBidRequests.map(bidRequest => {
- const {
- adUnitCode,
- auctionId,
- mediaTypes,
- params,
- sizes,
- transactionId
- } = bidRequest;
- const baseEndpoint = 'https://bidder.cleanmediaads.com';
- const rtbEndpoint =
- `${baseEndpoint}/r/${
- params.supplyPartnerId
- }/bidr?rformat=open_rtb&reqformat=rtb_json&bidder=prebid` +
- (params.query ? '&' + params.query : '');
- let url = bidderRequest.refererInfo.page;
-
+ const {adUnitCode, auctionId, mediaTypes, params, sizes, transactionId} = bidRequest;
+ const baseEndpoint = (params['rtbEndpoint'] || ENDPOINTS['cleanmedianet']).replace(/^http:/, 'https:');
+ const rtbEndpoint = `${baseEndpoint}/r/${params.supplyPartnerId}/bidr?rformat=open_rtb&reqformat=rtb_json&bidder=prebid` + (params.query ? '&' + params.query : '');
const rtbBidRequest = {
id: auctionId,
site: {
domain: bidderRequest.refererInfo.domain,
- page: url,
+ page: bidderRequest.refererInfo.page,
ref: bidderRequest.refererInfo.ref
},
device: {
@@ -81,44 +99,35 @@ export const spec = {
},
imp: [],
ext: {},
- user: {
- ext: {}
- }
+ user: {ext: {}},
+ source: {ext: {}},
+ regs: {ext: {}}
};
- if (
- bidderRequest.gdprConsent &&
- bidderRequest.gdprConsent.consentString &&
- bidderRequest.gdprConsent.gdprApplies
- ) {
- rtbBidRequest.ext.gdpr_consent = {
- consent_string: bidderRequest.gdprConsent.consentString,
- consent_required: bidderRequest.gdprConsent.gdprApplies
- };
- rtbBidRequest.regs = {
- ext: {
- gdpr: bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0
- }
- };
- rtbBidRequest.user = {
- ext: {
- consent: bidderRequest.gdprConsent.consentString
- }
- };
+ const gdprConsent = getGdprConsent(bidderRequest);
+ rtbBidRequest.ext.gdpr_consent = gdprConsent;
+ deepSetValue(rtbBidRequest, 'regs.ext.gdpr', gdprConsent.consent_required === true ? 1 : 0);
+ deepSetValue(rtbBidRequest, 'user.ext.consent', gdprConsent.consent_string);
+
+ if (validBidRequests[0].schain) {
+ deepSetValue(rtbBidRequest, 'source.ext.schain', validBidRequests[0].schain);
+ }
+
+ if (bidderRequest && bidderRequest.uspConsent) {
+ deepSetValue(rtbBidRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}
const imp = {
id: transactionId,
- instl: deepAccess(bidRequest.ortb2Imp, 'instl') === 1 || params.instl === 1 ? 1 : 0,
+ instl: deepAccess(bidderRequest.ortb2Imp, 'instl') === 1 || params.instl === 1 ? 1 : 0,
tagid: adUnitCode,
- bidfloor: 0,
+ bidfloor: helper.getBidFloor(bidRequest) || 0,
bidfloorcur: 'USD',
secure: 1
};
const hasFavoredMediaType =
- params.favoredMediaType &&
- includes(this.supportedMediaTypes, params.favoredMediaType);
+ params.favoredMediaType && includes(this.supportedMediaTypes, params.favoredMediaType);
if (!mediaTypes || mediaTypes.banner) {
if (!hasFavoredMediaType || params.favoredMediaType === BANNER) {
@@ -126,7 +135,7 @@ export const spec = {
banner: {
w: sizes.length ? sizes[0][0] : 300,
h: sizes.length ? sizes[0][1] : 250,
- pos: params.pos || 0,
+ pos: deepAccess(bidderRequest, 'mediaTypes.banner.pos') || params.pos || 0,
topframe: inIframe() ? 0 : 1
}
});
@@ -136,15 +145,25 @@ export const spec = {
if (mediaTypes && mediaTypes.video) {
if (!hasFavoredMediaType || params.favoredMediaType === VIDEO) {
- let videoImp = {
+ const playerSize = mediaTypes.video.playerSize || sizes;
+ const videoImp = Object.assign({}, imp, {
video: {
- protocols: params.protocols || [1, 2, 3, 4, 5, 6],
- pos: params.pos || 0,
- ext: {context: mediaTypes.video.context}
+ protocols: bidRequest.mediaTypes.video.protocols || params.protocols || [1, 2, 3, 4, 5, 6],
+ pos: deepAccess(bidRequest, 'mediaTypes.video.pos') || params.pos || 0,
+ ext: {
+ context: mediaTypes.video.context
+ },
+ mimes: bidRequest.mediaTypes.video.mimes,
+ maxduration: bidRequest.mediaTypes.video.maxduration,
+ api: bidRequest.mediaTypes.video.api,
+ skip: bidRequest.mediaTypes.video.skip || bidRequest.params.video.skip,
+ placement: bidRequest.mediaTypes.video.placement || bidRequest.params.video.placement,
+ minduration: bidRequest.mediaTypes.video.minduration || bidRequest.params.video.minduration,
+ playbackmethod: bidRequest.mediaTypes.video.playbackmethod || bidRequest.params.video.playbackmethod,
+ startdelay: bidRequest.mediaTypes.video.startdelay || bidRequest.params.video.startdelay
}
- };
+ });
- let playerSize = mediaTypes.video.playerSize || sizes;
if (isArray(playerSize[0])) {
videoImp.video.w = playerSize[0][0];
videoImp.video.h = playerSize[0][1];
@@ -156,11 +175,20 @@ export const spec = {
videoImp.video.h = 250;
}
- videoImp = Object.assign({}, imp, videoImp);
rtbBidRequest.imp.push(videoImp);
}
}
+ let eids = [];
+ if (bidRequest && bidRequest.userId) {
+ addExternalUserId(eids, deepAccess(bidRequest, `userId.id5id.uid`), 'id5-sync.com', 'ID5ID');
+ addExternalUserId(eids, deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 'TDID');
+ addExternalUserId(eids, deepAccess(bidRequest, `userId.idl_env`), 'liveramp.com', 'idl');
+ }
+ if (eids.length > 0) {
+ rtbBidRequest.user.ext.eids = eids;
+ }
+
if (rtbBidRequest.imp.length === 0) {
return;
}
@@ -181,10 +209,7 @@ export const spec = {
return [];
}
- const bids = response.seatbid.reduce(
- (acc, seatBid) => acc.concat(seatBid.bid),
- []
- );
+ const bids = response.seatbid.reduce((acc, seatBid) => acc.concat(seatBid.bid), []);
let outBids = [];
bids.forEach(bid => {
@@ -193,75 +218,81 @@ export const spec = {
cpm: bid.price,
width: bid.w,
height: bid.h,
- ttl: 360,
+ ttl: DEFAULT_TTL,
creativeId: bid.crid || bid.adid,
netRevenue: true,
currency: bid.cur || response.cur,
- mediaType: helper.getMediaType(bid)
+ mediaType: helper.getMediaType(bid),
};
- if (
- deepAccess(
- bidRequest.bidRequest,
- 'mediaTypes.' + outBid.mediaType
- )
- ) {
+ if (bid.adomain && bid.adomain.length) {
+ outBid.meta = {
+ advertiserDomains: bid.adomain
+ }
+ }
+
+ if (deepAccess(bidRequest.bidRequest, 'mediaTypes.' + outBid.mediaType)) {
if (outBid.mediaType === BANNER) {
outBids.push(Object.assign({}, outBid, {ad: bid.adm}));
} else if (outBid.mediaType === VIDEO) {
- const context = deepAccess(
- bidRequest.bidRequest,
- 'mediaTypes.video.context'
- );
- outBids.push(
- Object.assign({}, outBid, {
- vastUrl: bid.ext.vast_url,
- vastXml: bid.adm,
- renderer:
- context === 'outstream'
- ? newRenderer(bidRequest.bidRequest, bid)
- : undefined
- })
- );
+ const context = deepAccess(bidRequest.bidRequest, 'mediaTypes.video.context');
+ outBids.push(Object.assign({}, outBid, {
+ vastUrl: bid.ext.vast_url,
+ vastXml: bid.adm,
+ renderer: context === 'outstream' ? newRenderer(bidRequest.bidRequest, bid) : undefined
+ }));
}
}
});
return outBids;
},
- getUserSyncs: function (syncOptions, serverResponses, gdprConsent) {
+ getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) {
const syncs = [];
- const gdprApplies =
- gdprConsent && typeof gdprConsent.gdprApplies === 'boolean'
- ? gdprConsent.gdprApplies
- : false;
- const suffix = gdprApplies
- ? 'gc=' + encodeURIComponent(gdprConsent.consentString)
- : 'gc=missing';
+ let gdprApplies = false;
+ let consentString = '';
+ let uspConsentString = '';
+
+ if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) {
+ gdprApplies = gdprConsent.gdprApplies;
+ }
+ let gdpr = gdprApplies ? 1 : 0;
+
+ if (gdprApplies && gdprConsent.consentString) {
+ consentString = encodeURIComponent(gdprConsent.consentString);
+ }
+
+ if (uspConsent) {
+ uspConsentString = encodeURIComponent(uspConsent);
+ }
+
+ const macroValues = {
+ gdpr: gdpr,
+ consent: consentString,
+ uspConsent: uspConsentString
+ };
+
serverResponses.forEach(resp => {
if (resp.body) {
const bidResponse = resp.body;
if (bidResponse.ext && Array.isArray(bidResponse.ext['utrk'])) {
- bidResponse.ext['utrk'].forEach(pixel => {
- const url =
- pixel.url +
- (pixel.url.indexOf('?') > 0 ? '&' + suffix : '?' + suffix);
- return syncs.push({type: pixel.type, url});
- });
+ bidResponse.ext['utrk']
+ .forEach(pixel => {
+ const url = replaceMacros(pixel.url, macroValues);
+ syncs.push({type: pixel.type, url});
+ });
}
+
if (Array.isArray(bidResponse.seatbid)) {
bidResponse.seatbid.forEach(seatBid => {
if (Array.isArray(seatBid.bid)) {
seatBid.bid.forEach(bid => {
if (bid.ext && Array.isArray(bid.ext['utrk'])) {
- bid.ext['utrk'].forEach(pixel => {
- const url =
- pixel.url +
- (pixel.url.indexOf('?') > 0
- ? '&' + suffix
- : '?' + suffix);
- return syncs.push({type: pixel.type, url});
- });
+ bid.ext['utrk']
+ .forEach(pixel => {
+ const url = replaceMacros(pixel.url, macroValues);
+ syncs.push({type: pixel.type, url});
+ });
}
});
}
@@ -269,18 +300,16 @@ export const spec = {
}
}
});
+
return syncs;
}
};
function newRenderer(bidRequest, bid, rendererOptions = {}) {
const renderer = Renderer.install({
- url:
- (bidRequest.params && bidRequest.params.rendererUrl) ||
- (bid.ext && bid.ext.renderer_url) ||
- 'https://s.wlplayer.com/video/latest/renderer.js',
+ url: (bidRequest.params && bidRequest.params.rendererUrl) || (bid.ext && bid.ext.renderer_url) || 'https://s.gamoshi.io/video/latest/renderer.js',
config: rendererOptions,
- loaded: false
+ loaded: false,
});
try {
renderer.setRender(renderOutstream);
@@ -300,10 +329,9 @@ function renderOutstream(bid) {
width: bid.width,
height: bid.height,
events: {
- ALL_ADS_COMPLETED: () =>
- window.setTimeout(() => {
- window['GamoshiPlayer'].removeAd(unitId);
- }, 300)
+ ALL_ADS_COMPLETED: () => window.setTimeout(() => {
+ window['GamoshiPlayer'].removeAd(unitId);
+ }, 300)
},
vastUrl: bid.vastUrl,
vastXml: bid.vastXml
@@ -311,4 +339,41 @@ function renderOutstream(bid) {
});
}
+function addExternalUserId(eids, value, source, rtiPartner) {
+ if (isStr(value)) {
+ eids.push({
+ source,
+ uids: [{
+ id: value,
+ ext: {
+ rtiPartner
+ }
+ }]
+ });
+ }
+}
+
+function replaceMacros(url, macros) {
+ return url
+ .replace('[GDPR]', macros.gdpr)
+ .replace('[CONSENT]', macros.consent)
+ .replace('[US_PRIVACY]', macros.uspConsent);
+}
+
+function getGdprConsent(bidderRequest) {
+ const gdprConsent = bidderRequest.gdprConsent;
+
+ if (gdprConsent && gdprConsent.consentString && gdprConsent.gdprApplies) {
+ return {
+ consent_string: gdprConsent.consentString,
+ consent_required: gdprConsent.gdprApplies
+ };
+ }
+
+ return {
+ consent_required: false,
+ consent_string: '',
+ };
+}
+
registerBidder(spec);
diff --git a/modules/cleanmedianetBidAdapter.md b/modules/cleanmedianetBidAdapter.md
index f2bc8feb0f0..ee4e049e8d6 100644
--- a/modules/cleanmedianetBidAdapter.md
+++ b/modules/cleanmedianetBidAdapter.md
@@ -1,45 +1,49 @@
# Overview
```
-Module Name: Clean Media Net Adapter
+Module Name: CleanMedia Bid Adapter
Module Type: Bidder Adapter
-Maintainer: dev@cleanmedia.net
+Maintainer: dev@CleanMedia.net
```
# Description
-Connects to Clean Media Net's Programmatic advertising platform as a service.
+Connects to CleanMedia's Programmatic advertising platform as a service.
-Clean Media bid adapter supports Banner & Video (Instream and Outstream).
-The *only* required parameter (in the `params` section) is the `supplyPartnerId` parameter.
+CleanMedia bid adapter supports Banner & Outstream Video. The *only* required parameter (in the `params` section) is the `supplyPartnerId` parameter.
# Test Parameters
```
var adUnits = [
- // Banner adUnit
+
+ // Banner adUnit
{
code: 'banner-div',
sizes: [[300, 250]],
bids: [{
bidder: 'cleanmedianet',
params: {
- // ID of the supply partner you created in the Clean Media Net dashboard
+
+ // ID of the supply partner you created in the CleanMedia dashboard
supplyPartnerId: '1253',
- // OPTIONAL: custom bid floor
+
+ // OPTIONAL: custom bid floor
bidfloor: 0.01,
- // OPTIONAL: if you know the ad position on the page, specify it here
+
+ // OPTIONAL: if you know the ad position on the page, specify it here
// (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
//adpos: 1,
- // OPTIONAL: whether this is an interstitial placement (0 or 1)
+
+ // OPTIONAL: whether this is an interstitial placement (0 or 1)
// (see "instl" property in "Imp" object in the OpenRTB 2.3, section 3.2.2)
//instl: 0
}
}]
},
- // Video outstream adUnit
+
+ // Video outstream adUnit
{
code: 'video-outstream',
- sizes: [[300, 250]],
mediaTypes: {
video: {
context: 'outstream',
@@ -47,20 +51,62 @@ var adUnits = [
}
},
bids: [ {
- bidder: 'cleanmedianet',
+ bidder: 'CleanMedia',
params: {
- // ID of the supply partner you created in the dashboard
+
+ // ID of the supply partner you created in the dashboard
supplyPartnerId: '1254',
- // OPTIONAL: custom bid floor
+
+ // OPTIONAL: custom bid floor
bidfloor: 0.01,
- // OPTIONAL: if you know the ad position on the page, specify it here
+
+ // OPTIONAL: if you know the ad position on the page, specify it here
// (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
//adpos: 1,
- // OPTIONAL: whether this is an interstitial placement (0 or 1)
+
+ // OPTIONAL: whether this is an interstitial placement (0 or 1)
// (see "instl" property in "Imp" object in the OpenRTB 2.3, section 3.2.2)
//instl: 0
}
}]
- }
+ },
+
+ // Multi-Format adUnit
+ {
+ code: 'banner-div',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ playerSize: [300, 250]
+ },
+ banner: {
+ sizes: [[300, 250]]
+ }
+ },
+ bids: [{
+ bidder: 'CleanMedia',
+ params: {
+
+ // ID of the supply partner you created in the CleanMedia dashboard
+ supplyPartnerId: '1253',
+
+ // OPTIONAL: custom bid floor
+ bidfloor: 0.01,
+
+ // OPTIONAL: if you know the ad position on the page, specify it here
+ // (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
+ //adpos: 1,
+
+ // OPTIONAL: whether this is an interstitial placement (0 or 1)
+ // (see "instl" property in "Imp" object in the OpenRTB 2.3, section 3.2.2)
+ //instl: 0,
+
+ // OPTIONAL: enable enforcement bids of a specific media type (video, banner)
+ // in this ad placement
+ // query: 'key1=value1&k2=value2',
+ // favoredMediaType: 'video',
+ }
+ }]
+ },
];
```
diff --git a/test/spec/modules/cleanmedianetBidAdapter_spec.js b/test/spec/modules/cleanmedianetBidAdapter_spec.js
index 8c2ac34350b..a19cdf7fd35 100644
--- a/test/spec/modules/cleanmedianetBidAdapter_spec.js
+++ b/test/spec/modules/cleanmedianetBidAdapter_spec.js
@@ -2,96 +2,295 @@ import {expect} from 'chai';
import {spec, helper} from 'modules/cleanmedianetBidAdapter.js';
import * as utils from 'src/utils.js';
import {newBidder} from '../../../src/adapters/bidderFactory.js';
+import {deepClone} from 'src/utils';
const supplyPartnerId = '123';
const adapter = newBidder(spec);
-describe('CleanmedianetAdapter', function () {
- describe('Is String start with search ', function () {
- it('check if a string started with', function () {
- expect(helper.startsWith('cleanmediaads.com', 'cleanmediaads')).to.equal(
- true
- );
+const TTL = 360;
+
+describe('CleanmedianetAdapter', () => {
+ let schainConfig,
+ bidRequest,
+ bannerBidRequest,
+ videoBidRequest,
+ rtbResponse,
+ videoResponse,
+ gdprConsent;
+
+ beforeEach(() => {
+ schainConfig = {
+ 'ver': '1.0',
+ 'complete': 1,
+ 'nodes': [
+ {
+ 'asi': 'indirectseller.com',
+ 'sid': '00001',
+ 'hp': 1
+ },
+
+ {
+ 'asi': 'indirectseller-2.com',
+ 'sid': '00002',
+ 'hp': 2
+ }
+ ]
+ };
+
+ bidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ banner: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [[300, 250], [300, 600]],
+ 'transactionId': 'a123456789',
+ refererInfo: {referer: 'http://examplereferer.com'},
+ gdprConsent: {
+ consentString: 'some string',
+ gdprApplies: true
+ },
+ schain: schainConfig,
+ uspConsent: 'cleanmediaCCPA'
+ };
+
+ bannerBidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ banner: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [[300, 250], [300, 600]],
+ 'transactionId': 'a123456789',
+ 'bidId': '111',
+ refererInfo: {referer: 'http://examplereferer.com'}
+ };
+
+ videoBidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ video: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [[300, 250], [300, 600]],
+ 'transactionId': 'a123456789',
+ 'bidId': '111',
+ refererInfo: {referer: 'http://examplereferer.com'}
+ };
+
+ rtbResponse = {
+ 'id': 'imp_5b05b9fde4b09084267a556f',
+ 'bidid': 'imp_5b05b9fde4b09084267a556f',
+ 'cur': 'USD',
+ 'ext': {
+ 'utrk': [
+ {'type': 'iframe', 'url': '//bidder.cleanmediaads.com/user/sync/1?gdpr=[GDPR]&consent=[CONSENT]&usp=[US_PRIVACY]'},
+ {'type': 'image', 'url': '//bidder.cleanmediaads.com/user/sync/2'}
+ ]
+ },
+ 'seatbid': [
+ {
+ 'seat': 'seat1',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': '0',
+ 'impid': '1',
+ 'price': 2.016,
+ 'adid': '579ef31bfa788b9d2000d562',
+ 'nurl': 'https://bidder.cleanmediaads.com/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0',
+ 'adm': '↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵',
+ 'adomain': ['aaa.com'],
+ 'cid': '579ef268fa788b9d2000d55c',
+ 'crid': '579ef31bfa788b9d2000d562',
+ 'attr': [],
+ 'h': 600,
+ 'w': 120,
+ 'ext': {
+ 'vast_url': 'http://my.vast.com',
+ 'utrk': [
+ {'type': 'iframe', 'url': '//p.partner1.io/user/sync/1'}
+ ]
+ }
+ }
+ ]
+ },
+ {
+ 'seat': 'seat2',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': '1',
+ 'impid': '1',
+ 'price': 3,
+ 'adid': '542jlhdfd2112jnjf3x',
+ 'nurl': 'https://bidder.cleanmediaads.com/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0',
+ 'adm': ' ',
+ 'adomain': ['bbb.com'],
+ 'cid': 'fgdlwjh2498ydjhg1',
+ 'crid': 'kjh34297ydh2133d',
+ 'attr': [],
+ 'h': 250,
+ 'w': 300,
+ 'ext': {
+ 'utrk': [
+ {'type': 'image', 'url': '//p.partner2.io/user/sync/1'}
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ };
+
+ videoResponse = {
+ 'id': '64f32497-b2f7-48ec-9205-35fc39894d44',
+ 'bidid': 'imp_5c24924de4b0d106447af333',
+ 'cur': 'USD',
+ 'seatbid': [
+ {
+ 'seat': '3668',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': 'gb_1',
+ 'impid': 'afbb5852-7cea-4a81-aa9a-a41aab505c23',
+ 'price': 5.0,
+ 'adid': '1274',
+ 'nurl': 'https://bidder.cleanmediaads.com/pix/1275/win_notice/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1',
+ 'adomain': [],
+ 'adm': '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
+ 'cid': '3668',
+ 'crid': '1274',
+ 'cat': [],
+ 'attr': [],
+ 'h': 250,
+ 'w': 300,
+ 'ext': {
+ 'vast_url': 'https://bidder.cleanmediaads.com/pix/1275/vast_o/imp_5c24924de4b0d106447af333/im.xml?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1&w=300&h=250&vatu=aHR0cHM6Ly9zdGF0aWMuZ2FtYmlkLmlvL2RlbW8vdmFzdC54bWw&vwarv',
+ 'imptrackers': [
+ 'https://bidder.cleanmediaads.com/pix/1275/imp/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1']
+ }
+ }
+ ]
+ }
+ ],
+ 'ext': {
+ 'utrk': [{
+ 'type': 'image',
+ 'url': 'https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gdpr=[GDPR]&consent=[CONSENT]&us_privacy=[US_PRIVACY]'
+ }]
+ }
+ };
+
+ gdprConsent = {
+ gdprApplies: true,
+ consentString: 'consent string'
+ };
+ });
+
+ describe('Get top Frame', () => {
+ it('check if you are in the top frame', () => {
+ expect(helper.getTopFrame()).to.equal(0);
+ });
+ });
+
+ describe('Is String start with search', () => {
+ it('check if a string started with', () => {
+ expect(helper.startsWith('cleanmedia.net', 'clea')).to.equal(true);
});
});
- describe('inherited functions', function() {
- it('exists and is a function', function() {
+ describe('inherited functions', () => {
+ it('exists and is a function', () => {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});
- describe('isBidRequestValid', function() {
- it('should validate supply-partner ID', function() {
- expect(spec.isBidRequestValid({ params: {} })).to.equal(false);
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: 123 } })
- ).to.equal(false);
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })
- ).to.equal(true);
+ describe('isBidRequestValid', () => {
+ it('should validate supply-partner ID', () => {
+ expect(spec.isBidRequestValid({params: {}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: 123}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123'}})).to.equal(true);
+ });
+
+ it('should validate RTB endpoint', () => {
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123'}})).to.equal(true); // RTB endpoint has a default
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', rtbEndpoint: 123}})).to.equal(false);
+ expect(spec.isBidRequestValid({
+ params: {
+ supplyPartnerId: '123',
+ rtbEndpoint: 'https://some.url.com'
+ }
+ })).to.equal(true);
+ });
+
+ it('should validate bid floor', () => {
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123'}})).to.equal(true); // bidfloor has a default
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', bidfloor: '123'}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', bidfloor: 0.1}})).to.equal(true);
+
+ const getFloorResponse = {currency: 'USD', floor: 5};
+ let testBidRequest = deepClone(bidRequest);
+ let request = spec.buildRequests([testBidRequest], bidRequest)[0];
+
+ // 1. getBidFloor not exist AND bidfloor not exist - return 0
+ let payload = request.data;
+ expect(payload.imp[0].bidfloor).to.exist.and.equal(0);
+
+ // 2. getBidFloor not exist AND bidfloor exist - use bidfloor property
+ testBidRequest = deepClone(bidRequest);
+ testBidRequest.params = {
+ 'bidfloor': 0.3
+ };
+ request = spec.buildRequests([testBidRequest], bidRequest)[0];
+ payload = request.data;
+ expect(payload.imp[0].bidfloor).to.exist.and.to.equal(0.3)
+
+ // 3. getBidFloor exist AND bidfloor not exist - use getFloor method
+ testBidRequest = deepClone(bidRequest);
+ testBidRequest.getFloor = () => getFloorResponse;
+ request = spec.buildRequests([testBidRequest], bidRequest)[0];
+ payload = request.data;
+ expect(payload.imp[0].bidfloor).to.exist.and.to.equal(5)
+
+ // 4. getBidFloor exist AND bidfloor exist -> use getFloor method
+ testBidRequest = deepClone(bidRequest);
+ testBidRequest.getFloor = () => getFloorResponse;
+ testBidRequest.params = {
+ 'bidfloor': 0.3
+ };
+ request = spec.buildRequests([testBidRequest], bidRequest)[0];
+ payload = request.data;
+ expect(payload.imp[0].bidfloor).to.exist.and.to.equal(5)
});
- it('should validate adpos', function() {
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })
- ).to.equal(true); // adpos has a default
- expect(
- spec.isBidRequestValid({
- params: { supplyPartnerId: '123', adpos: '123' }
- })
- ).to.equal(false);
- expect(
- spec.isBidRequestValid({
- params: { supplyPartnerId: '123', adpos: 0.1 }
- })
- ).to.equal(true);
+ it('should validate adpos', () => {
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123'}})).to.equal(true); // adpos has a default
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', adpos: '123'}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', adpos: 0.1}})).to.equal(true);
});
- it('should validate instl', function() {
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })
- ).to.equal(true); // adpos has a default
- expect(
- spec.isBidRequestValid({
- params: { supplyPartnerId: '123', instl: '123' }
- })
- ).to.equal(false);
- expect(
- spec.isBidRequestValid({
- params: { supplyPartnerId: '123', instl: -1 }
- })
- ).to.equal(false);
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 0 } })
- ).to.equal(true);
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 1 } })
- ).to.equal(true);
- expect(
- spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 2 } })
- ).to.equal(false);
+ it('should validate instl', () => {
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123'}})).to.equal(true); // adpos has a default
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', instl: '123'}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', instl: -1}})).to.equal(false);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', instl: 0}})).to.equal(true);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', instl: 1}})).to.equal(true);
+ expect(spec.isBidRequestValid({params: {supplyPartnerId: '123', instl: 2}})).to.equal(false);
});
});
- describe('buildRequests', function() {
- const bidRequest = {
- adUnitCode: 'adunit-code',
- auctionId: '1d1a030790a475',
- mediaTypes: {
- banner: {}
- },
- params: {
- supplyPartnerId: supplyPartnerId
- },
- sizes: [[300, 250], [300, 600]],
- transactionId: 'a123456789',
- refererInfo: { referer: 'https://examplereferer.com', domain: 'examplereferer.com' },
- gdprConsent: {
- consentString: 'some string',
- gdprApplies: true
- }
- };
- it('returns an array', function() {
+ describe('buildRequests', () => {
+ it('returns an array', () => {
let response;
response = spec.buildRequests([]);
expect(Array.isArray(response)).to.equal(true);
@@ -99,58 +298,61 @@ describe('CleanmedianetAdapter', function () {
response = spec.buildRequests([bidRequest], bidRequest);
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(1);
- const adUnit1 = Object.assign({}, utils.deepClone(bidRequest), {
- auctionId: '1',
- adUnitCode: 'a'
- });
- const adUnit2 = Object.assign({}, utils.deepClone(bidRequest), {
- auctionId: '1',
- adUnitCode: 'b'
- });
+ const adUnit1 = Object.assign({}, utils.deepClone(bidRequest), {auctionId: '1', adUnitCode: 'a'});
+ const adUnit2 = Object.assign({}, utils.deepClone(bidRequest), {auctionId: '1', adUnitCode: 'b'});
response = spec.buildRequests([adUnit1, adUnit2], bidRequest);
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(2);
});
- it('builds request correctly', function() {
+ it('targets correct endpoint', () => {
+ let response;
+ response = spec.buildRequests([bidRequest], bidRequest)[0];
+ expect(response.method).to.equal('POST');
+ expect(response.url).to.match(new RegExp(`^https://bidder\\.cleanmediaads\\.com/r/${supplyPartnerId}/bidr\\?rformat=open_rtb&reqformat=rtb_json&bidder=prebid$`, 'g'));
+ expect(response.data.id).to.equal(bidRequest.auctionId);
+ const bidRequestWithEndpoint = utils.deepClone(bidRequest);
+ bidRequestWithEndpoint.params.rtbEndpoint = 'https://bidder.cleanmediaads.com/a12';
+ response = spec.buildRequests([bidRequestWithEndpoint], bidRequest)[0];
+ expect(response.url).to.match(new RegExp(`^https://bidder\\.cleanmediaads\\.com/a12/r/${supplyPartnerId}/bidr\\?rformat=open_rtb&reqformat=rtb_json&bidder=prebid$`, 'g'));
+ });
+
+ it('builds request correctly', () => {
let bidRequest2 = utils.deepClone(bidRequest);
Object.assign(bidRequest2.refererInfo, {
- page: 'https://www.test.com/page.html',
- domain: 'test.com',
- ref: 'https://referer.com'
+ page: 'http://www.test.com/page.html',
+ domain: 'www.test.com',
+ ref: 'http://referrer.com'
})
-
let response = spec.buildRequests([bidRequest], bidRequest2)[0];
- expect(response.data.site.domain).to.equal('test.com');
- expect(response.data.site.page).to.equal('https://www.test.com/page.html');
- expect(response.data.site.ref).to.equal('https://referer.com');
+
+ expect(response.data.site.domain).to.equal('www.test.com');
+ expect(response.data.site.page).to.equal('http://www.test.com/page.html');
+ expect(response.data.site.ref).to.equal('http://referrer.com');
expect(response.data.imp.length).to.equal(1);
expect(response.data.imp[0].id).to.equal(bidRequest.transactionId);
expect(response.data.imp[0].instl).to.equal(0);
expect(response.data.imp[0].tagid).to.equal(bidRequest.adUnitCode);
expect(response.data.imp[0].bidfloor).to.equal(0);
expect(response.data.imp[0].bidfloorcur).to.equal('USD');
+ expect(response.data.regs.ext.us_privacy).to.equal('cleanmediaCCPA');// USP/CCPAs
+ expect(response.data.source.ext.schain).to.deep.equal(bidRequest2.schain);
+
const bidRequestWithInstlEquals1 = utils.deepClone(bidRequest);
bidRequestWithInstlEquals1.params.instl = 1;
- response = spec.buildRequests(
- [bidRequestWithInstlEquals1],
- bidRequest2
- )[0];
- expect(response.data.imp[0].instl).to.equal(
- bidRequestWithInstlEquals1.params.instl
- );
+ response = spec.buildRequests([bidRequestWithInstlEquals1], bidRequest2)[0];
+ expect(response.data.imp[0].instl).to.equal(bidRequestWithInstlEquals1.params.instl);
const bidRequestWithInstlEquals0 = utils.deepClone(bidRequest);
bidRequestWithInstlEquals0.params.instl = 1;
- response = spec.buildRequests(
- [bidRequestWithInstlEquals0],
- bidRequest2
- )[0];
- expect(response.data.imp[0].instl).to.equal(
- bidRequestWithInstlEquals0.params.instl
- );
+ response = spec.buildRequests([bidRequestWithInstlEquals0], bidRequest2)[0];
+ expect(response.data.imp[0].instl).to.equal(bidRequestWithInstlEquals0.params.instl);
+ const bidRequestWithBidfloorEquals1 = utils.deepClone(bidRequest);
+ bidRequestWithBidfloorEquals1.params.bidfloor = 1;
+ response = spec.buildRequests([bidRequestWithBidfloorEquals1], bidRequest2)[0];
+ expect(response.data.imp[0].bidfloor).to.equal(bidRequestWithBidfloorEquals1.params.bidfloor);
});
- it('builds request banner object correctly', function() {
+ it('builds request banner object correctly', () => {
let response;
const bidRequestWithBanner = utils.deepClone(bidRequest);
bidRequestWithBanner.mediaTypes = {
@@ -159,54 +361,80 @@ describe('CleanmedianetAdapter', function () {
}
};
response = spec.buildRequests([bidRequestWithBanner], bidRequest)[0];
- expect(response.data.imp[0].banner.w).to.equal(
- bidRequestWithBanner.mediaTypes.banner.sizes[0][0]
- );
- expect(response.data.imp[0].banner.h).to.equal(
- bidRequestWithBanner.mediaTypes.banner.sizes[0][1]
- );
+ expect(response.data.imp[0].banner.w).to.equal(bidRequestWithBanner.mediaTypes.banner.sizes[0][0]);
+ expect(response.data.imp[0].banner.h).to.equal(bidRequestWithBanner.mediaTypes.banner.sizes[0][1]);
expect(response.data.imp[0].banner.pos).to.equal(0);
+ expect(response.data.imp[0].banner.topframe).to.equal(0);
const bidRequestWithPosEquals1 = utils.deepClone(bidRequestWithBanner);
bidRequestWithPosEquals1.params.pos = 1;
response = spec.buildRequests([bidRequestWithPosEquals1], bidRequest)[0];
- expect(response.data.imp[0].banner.pos).to.equal(
- bidRequestWithPosEquals1.params.pos
- );
+ expect(response.data.imp[0].banner.pos).to.equal(bidRequestWithPosEquals1.params.pos);
});
- it('builds request video object correctly', function() {
+ it('builds request video object correctly', () => {
let response;
const bidRequestWithVideo = utils.deepClone(bidRequest);
+
+ bidRequestWithVideo.params.video = {
+ placement: 1,
+ minduration: 1,
+ }
+
bidRequestWithVideo.mediaTypes = {
video: {
- sizes: [[300, 250], [120, 600]]
+ playerSize: [[302, 252]],
+ mimes: ['video/mpeg'],
+ playbackmethod: 1,
+ startdelay: 1,
}
};
response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
- expect(response.data.imp[0].video.w).to.equal(
- bidRequestWithVideo.mediaTypes.video.sizes[0][0]
- );
- expect(response.data.imp[0].video.h).to.equal(
- bidRequestWithVideo.mediaTypes.video.sizes[0][1]
- );
+ expect(response.data.imp[0].video.w).to.equal(bidRequestWithVideo.mediaTypes.video.playerSize[0][0]);
+ expect(response.data.imp[0].video.h).to.equal(bidRequestWithVideo.mediaTypes.video.playerSize[0][1]);
expect(response.data.imp[0].video.pos).to.equal(0);
+
+ expect(response.data.imp[0].video.mimes).to.equal(bidRequestWithVideo.mediaTypes.video.mimes);
+ expect(response.data.imp[0].video.skip).to.not.exist;
+ expect(response.data.imp[0].video.placement).to.equal(1);
+ expect(response.data.imp[0].video.minduration).to.equal(1);
+ expect(response.data.imp[0].video.playbackmethod).to.equal(1);
+ expect(response.data.imp[0].video.startdelay).to.equal(1);
+
+ bidRequestWithVideo.mediaTypes = {
+ video: {
+ playerSize: [302, 252],
+ mimes: ['video/mpeg'],
+ skip: 1,
+ placement: 1,
+ minduration: 1,
+ playbackmethod: 1,
+ startdelay: 1,
+ },
+ };
+
const bidRequestWithPosEquals1 = utils.deepClone(bidRequestWithVideo);
+ expect(response.data.imp[0].video.w).to.equal(bidRequestWithVideo.mediaTypes.video.playerSize[0]);
+ expect(response.data.imp[0].video.h).to.equal(bidRequestWithVideo.mediaTypes.video.playerSize[1]);
+
bidRequestWithPosEquals1.params.pos = 1;
response = spec.buildRequests([bidRequestWithPosEquals1], bidRequest)[0];
- expect(response.data.imp[0].video.pos).to.equal(
- bidRequestWithPosEquals1.params.pos
- );
+ expect(response.data.imp[0].video.pos).to.equal(bidRequestWithPosEquals1.params.pos);
});
- it('builds request video object correctly with context', function() {
- let response;
+ it('builds request video object correctly with context', () => {
const bidRequestWithVideo = utils.deepClone(bidRequest);
bidRequestWithVideo.mediaTypes = {
video: {
- context: 'instream'
+ context: 'instream',
+ mimes: ['video/mpeg'],
+ skip: 1,
+ placement: 1,
+ minduration: 1,
+ playbackmethod: 1,
+ startdelay: 1,
}
};
- response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
+ let response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
expect(response.data.imp[0].video.ext.context).to.equal('instream');
bidRequestWithVideo.mediaTypes.video.context = 'outstream';
@@ -220,358 +448,185 @@ describe('CleanmedianetAdapter', function () {
response = spec.buildRequests([bidRequestWithPosEquals2], bidRequest)[0];
expect(response.data.imp[0].video.ext.context).to.equal(null);
});
- it('builds request video object correctly with multi-dimensions size array', function () {
- let bidRequestWithVideo = utils.deepClone(bidRequest);
+
+ it('builds request video object correctly with multi-dimensions size array', () => {
+ let response;
+ const bidRequestWithVideo = utils.deepClone(bidRequest);
bidRequestWithVideo.mediaTypes.video = {
playerSize: [[304, 254], [305, 255]],
- context: 'instream'
+ context: 'instream',
+ mimes: ['video/mpeg'],
+ skip: 1,
+ placement: 1,
+ minduration: 1,
+ playbackmethod: 1,
+ startdelay: 1,
};
- let response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
- expect(response.data.imp[1].video.w).to.equal(304);
- expect(response.data.imp[1].video.h).to.equal(254);
+ response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
+ expect(response.data.imp[1].video.ext.context).to.equal('instream');
+ bidRequestWithVideo.mediaTypes.video.context = 'outstream';
- bidRequestWithVideo = utils.deepClone(bidRequest);
- bidRequestWithVideo.mediaTypes.video = {
- playerSize: [304, 254]
- };
+ const bidRequestWithPosEquals1 = utils.deepClone(bidRequestWithVideo);
+ bidRequestWithPosEquals1.mediaTypes.video.context = 'outstream';
+ response = spec.buildRequests([bidRequestWithPosEquals1], bidRequest)[0];
+ expect(response.data.imp[1].video.ext.context).to.equal('outstream');
- response = spec.buildRequests([bidRequestWithVideo], bidRequest)[0];
- expect(response.data.imp[1].video.w).to.equal(304);
- expect(response.data.imp[1].video.h).to.equal(254);
+ const bidRequestWithPosEquals2 = utils.deepClone(bidRequestWithVideo);
+ bidRequestWithPosEquals2.mediaTypes.video.context = null;
+ response = spec.buildRequests([bidRequestWithPosEquals2], bidRequest)[0];
+ expect(response.data.imp[1].video.ext.context).to.equal(null);
});
- it('builds request with gdpr consent', function() {
+ it('builds request with gdpr consent', () => {
let response = spec.buildRequests([bidRequest], bidRequest)[0];
+
+ expect(response.data.ext.gdpr_consent).to.not.equal(null).and.not.equal(undefined);
expect(response.data.ext).to.have.property('gdpr_consent');
- expect(response.data.ext.gdpr_consent.consent_string).to.equal(
- 'some string'
- );
+ expect(response.data.ext.gdpr_consent.consent_string).to.equal('some string');
expect(response.data.ext.gdpr_consent.consent_required).to.equal(true);
- });
- });
-
- describe('interpretResponse', function() {
- const bannerBidRequest = {
- adUnitCode: 'adunit-code',
- auctionId: '1d1a030790a475',
- mediaTypes: {
- banner: {}
- },
- params: {
- supplyPartnerId: supplyPartnerId
- },
- sizes: [[300, 250], [300, 600]],
- transactionId: 'a123456789',
- bidId: '111',
- refererInfo: { referer: 'https://examplereferer.com' }
- };
- const videoBidRequest = {
- adUnitCode: 'adunit-code',
- auctionId: '1d1a030790a475',
- mediaTypes: {
- video: {}
- },
- params: {
- supplyPartnerId: supplyPartnerId
- },
- sizes: [[300, 250], [300, 600]],
- transactionId: 'a123456789',
- bidId: '111',
- refererInfo: { referer: 'https://examplereferer.com' }
- };
+ expect(response.data.regs.ext.gdpr).to.not.equal(null).and.not.equal(undefined);
+ expect(response.data.user.ext.consent).to.equal('some string');
+ });
- const rtbResponse = {
- id: 'imp_5b05b9fde4b09084267a556f',
- bidid: 'imp_5b05b9fde4b09084267a556f',
- cur: 'USD',
- ext: {
- utrk: [
- { type: 'iframe', url: '//bidder.cleanmediaads.com/user/sync/1' },
- { type: 'image', url: '//bidder.cleanmediaads.com/user/sync/2' }
- ]
- },
- seatbid: [
- {
- seat: 'seat1',
- group: 0,
- bid: [
- {
- id: '0',
- impid: '1',
- price: 2.016,
- adid: '579ef31bfa788b9d2000d562',
- nurl:
- 'https://bidder.cleanmediaads.com/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0',
- adm:
- '↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵↵',
- adomain: ['aaa.com'],
- cid: '579ef268fa788b9d2000d55c',
- crid: '579ef31bfa788b9d2000d562',
- attr: [],
- h: 600,
- w: 120,
- ext: {
- vast_url: 'https://my.vast.com',
- utrk: [{ type: 'iframe', url: '//p.partner1.io/user/sync/1' }]
- }
- }
- ]
- },
- {
- seat: 'seat2',
- group: 0,
- bid: [
- {
- id: '1',
- impid: '1',
- price: 3,
- adid: '542jlhdfd2112jnjf3x',
- nurl:
- 'https://bidder.cleanmediaads.com/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0',
- adm:
- ' ',
- adomain: ['bbb.com'],
- cid: 'fgdlwjh2498ydjhg1',
- crid: 'kjh34297ydh2133d',
- attr: [],
- h: 250,
- w: 300,
- ext: {
- utrk: [{ type: 'image', url: '//p.partner2.io/user/sync/1' }]
- }
- }
- ]
- }
- ]
- };
+ it('build request with ID5 Id', () => {
+ const bidRequestClone = utils.deepClone(bidRequest);
+ bidRequestClone.userId = {};
+ bidRequestClone.userId.id5id = { uid: 'id5-user-id' };
+ let request = spec.buildRequests([bidRequestClone], bidRequestClone)[0];
+ expect(request.data.user.ext.eids).to.deep.equal([{
+ 'source': 'id5-sync.com',
+ 'uids': [{
+ 'id': 'id5-user-id',
+ 'ext': {
+ 'rtiPartner': 'ID5ID'
+ }
+ }]
+ }]);
+ });
- it('returns an empty array on missing response', function() {
- let response;
+ it('build request with unified Id', () => {
+ const bidRequestClone = utils.deepClone(bidRequest);
+ bidRequestClone.userId = {};
+ bidRequestClone.userId.tdid = 'tdid-user-id';
+ let request = spec.buildRequests([bidRequestClone], bidRequestClone)[0];
+ expect(request.data.user.ext.eids).to.deep.equal([{
+ 'source': 'adserver.org',
+ 'uids': [{
+ 'id': 'tdid-user-id',
+ 'ext': {
+ 'rtiPartner': 'TDID'
+ }
+ }]
+ }]);
+ });
+ });
- response = spec.interpretResponse(undefined, {
- bidRequest: bannerBidRequest
- });
+ describe('interpretResponse', () => {
+ it('returns an empty array on missing response', () => {
+ let response = spec.interpretResponse(undefined, {bidRequest: bannerBidRequest});
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(0);
- response = spec.interpretResponse({}, { bidRequest: bannerBidRequest });
+ response = spec.interpretResponse({}, {bidRequest: bannerBidRequest});
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(0);
});
- it('aggregates banner bids from all seat bids', function() {
- const response = spec.interpretResponse(
- { body: rtbResponse },
- { bidRequest: bannerBidRequest }
- );
+ it('aggregates banner bids from all seat bids', () => {
+ const response = spec.interpretResponse({body: rtbResponse}, {bidRequest: bannerBidRequest});
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(1);
-
const ad0 = response[0];
expect(ad0.requestId).to.equal(bannerBidRequest.bidId);
expect(ad0.cpm).to.equal(rtbResponse.seatbid[1].bid[0].price);
expect(ad0.width).to.equal(rtbResponse.seatbid[1].bid[0].w);
expect(ad0.height).to.equal(rtbResponse.seatbid[1].bid[0].h);
- expect(ad0.ttl).to.equal(360);
+ expect(ad0.ttl).to.equal(TTL);
expect(ad0.creativeId).to.equal(rtbResponse.seatbid[1].bid[0].crid);
expect(ad0.netRevenue).to.equal(true);
- expect(ad0.currency).to.equal(
- rtbResponse.seatbid[1].bid[0].cur || rtbResponse.cur || 'USD'
- );
+ expect(ad0.currency).to.equal(rtbResponse.seatbid[1].bid[0].cur || rtbResponse.cur || 'USD');
expect(ad0.ad).to.equal(rtbResponse.seatbid[1].bid[0].adm);
expect(ad0.vastXml).to.be.an('undefined');
expect(ad0.vastUrl).to.be.an('undefined');
+ expect(ad0.meta.advertiserDomains).to.be.equal(rtbResponse.seatbid[1].bid[0].adomain);
});
- it('aggregates video bids from all seat bids', function() {
- const response = spec.interpretResponse(
- { body: rtbResponse },
- { bidRequest: videoBidRequest }
- );
+ it('aggregates video bids from all seat bids', () => {
+ const response = spec.interpretResponse({body: rtbResponse}, {bidRequest: videoBidRequest});
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(1);
-
const ad0 = response[0];
expect(ad0.requestId).to.equal(videoBidRequest.bidId);
expect(ad0.cpm).to.equal(rtbResponse.seatbid[0].bid[0].price);
expect(ad0.width).to.equal(rtbResponse.seatbid[0].bid[0].w);
expect(ad0.height).to.equal(rtbResponse.seatbid[0].bid[0].h);
- expect(ad0.ttl).to.equal(360);
+ expect(ad0.ttl).to.equal(TTL);
expect(ad0.creativeId).to.equal(rtbResponse.seatbid[0].bid[0].crid);
expect(ad0.netRevenue).to.equal(true);
- expect(ad0.currency).to.equal(
- rtbResponse.seatbid[0].bid[0].cur || rtbResponse.cur || 'USD'
- );
+ expect(ad0.currency).to.equal(rtbResponse.seatbid[0].bid[0].cur || rtbResponse.cur || 'USD');
expect(ad0.ad).to.be.an('undefined');
expect(ad0.vastXml).to.equal(rtbResponse.seatbid[0].bid[0].adm);
expect(ad0.vastUrl).to.equal(rtbResponse.seatbid[0].bid[0].ext.vast_url);
});
- it('aggregates user-sync pixels', function() {
- const response = spec.getUserSyncs({}, [{ body: rtbResponse }]);
+ it('aggregates user-sync pixels', () => {
+ const response = spec.getUserSyncs({}, [{body: rtbResponse}]);
expect(Array.isArray(response)).to.equal(true);
expect(response.length).to.equal(4);
expect(response[0].type).to.equal(rtbResponse.ext.utrk[0].type);
- expect(response[0].url).to.equal(
- rtbResponse.ext.utrk[0].url + '?gc=missing'
- );
+ expect(response[0].url).to.equal('//bidder.cleanmediaads.com/user/sync/1?gdpr=0&consent=&usp=');
expect(response[1].type).to.equal(rtbResponse.ext.utrk[1].type);
- expect(response[1].url).to.equal(
- rtbResponse.ext.utrk[1].url + '?gc=missing'
- );
- expect(response[2].type).to.equal(
- rtbResponse.seatbid[0].bid[0].ext.utrk[0].type
- );
- expect(response[2].url).to.equal(
- rtbResponse.seatbid[0].bid[0].ext.utrk[0].url + '?gc=missing'
- );
- expect(response[3].type).to.equal(
- rtbResponse.seatbid[1].bid[0].ext.utrk[0].type
- );
- expect(response[3].url).to.equal(
- rtbResponse.seatbid[1].bid[0].ext.utrk[0].url + '?gc=missing'
- );
+ expect(response[1].url).to.equal('//bidder.cleanmediaads.com/user/sync/2');
+ expect(response[2].type).to.equal(rtbResponse.seatbid[0].bid[0].ext.utrk[0].type);
+ expect(response[2].url).to.equal('//p.partner1.io/user/sync/1');
+ expect(response[3].type).to.equal(rtbResponse.seatbid[1].bid[0].ext.utrk[0].type);
+ expect(response[3].url).to.equal('//p.partner2.io/user/sync/1');
});
- it('supports configuring outstream renderers', function() {
- const videoResponse = {
- id: '64f32497-b2f7-48ec-9205-35fc39894d44',
- bidid: 'imp_5c24924de4b0d106447af333',
- cur: 'USD',
- seatbid: [
- {
- seat: '3668',
- group: 0,
- bid: [
- {
- id: 'gb_1',
- impid: 'afbb5852-7cea-4a81-aa9a-a41aab505c23',
- price: 5.0,
- adid: '1274',
- nurl:
- 'https://bidder.cleanmediaads.com/pix/1275/win_notice/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1',
- adomain: [],
- adm:
- '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
- cid: '3668',
- crid: '1274',
- cat: [],
- attr: [],
- h: 250,
- w: 300,
- ext: {
- vast_url:
- 'https://bidder.cleanmediaads.com/pix/1275/vast_o/imp_5c24924de4b0d106447af333/im.xml?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1&w=300&h=250&vatu=aHR0cHM6Ly9zdGF0aWMuZ2FtYmlkLmlvL2RlbW8vdmFzdC54bWw&vwarv',
- imptrackers: [
- 'https://bidder.cleanmediaads.com/pix/1275/imp/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1'
- ]
- }
- }
- ]
- }
- ],
- ext: {
- utrk: [
- {
- type: 'image',
- url:
- 'https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675'
- }
- ]
- }
- };
+ it('supports configuring outstream renderers', () => {
const videoRequest = utils.deepClone(videoBidRequest);
videoRequest.mediaTypes.video.context = 'outstream';
- const result = spec.interpretResponse(
- { body: videoResponse },
- { bidRequest: videoRequest }
- );
+ const result = spec.interpretResponse({body: videoResponse}, {bidRequest: videoRequest});
expect(result[0].renderer).to.not.equal(undefined);
});
- it('validates in/existing of gdpr consent', function() {
- let videoResponse = {
- id: '64f32497-b2f7-48ec-9205-35fc39894d44',
- bidid: 'imp_5c24924de4b0d106447af333',
- cur: 'USD',
- seatbid: [
- {
- seat: '3668',
- group: 0,
- bid: [
- {
- id: 'gb_1',
- impid: 'afbb5852-7cea-4a81-aa9a-a41aab505c23',
- price: 5.0,
- adid: '1274',
- nurl:
- 'https://bidder.cleanmediaads.com/pix/1275/win_notice/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1',
- adomain: [],
- adm:
- '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
- cid: '3668',
- crid: '1274',
- cat: [],
- attr: [],
- h: 250,
- w: 300,
- ext: {
- vast_url:
- 'https://bidder.cleanmediaads.com/pix/1275/vast_o/imp_5c24924de4b0d106447af333/im.xml?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1&w=300&h=250&vatu=aHR0cHM6Ly9zdGF0aWMuZ2FtYmlkLmlvL2RlbW8vdmFzdC54bWw&vwarv',
- imptrackers: [
- 'https://bidder.cleanmediaads.com/pix/1275/imp/imp_5c24924de4b0d106447af333/im.gif?r=imp_5c24924de4b0d106447af333&i=afbb5852-7cea-4a81-aa9a-a41aab505c23&a=1274&b=gb_1'
- ]
- }
- }
- ]
- }
- ],
- ext: {
- utrk: [
- {
- type: 'image',
- url:
- 'https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675'
- }
- ]
- }
- };
- let gdprConsent = {
- gdprApplies: true,
- consentString: 'consent string'
- };
- let result = spec.getUserSyncs(
- {},
- [{ body: videoResponse }],
- gdprConsent
- );
+ it('validates in/existing of gdpr consent', () => {
+ let result = spec.getUserSyncs({}, [{body: videoResponse}], gdprConsent, 'cleanmediaCCPA');
expect(result).to.be.an('array');
expect(result.length).to.equal(1);
expect(result[0].type).to.equal('image');
- expect(result[0].url).to.equal(
- 'https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gc=consent%20string'
- );
+ expect(result[0].url).to.equal('https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gdpr=1&consent=consent%20string&us_privacy=cleanmediaCCPA');
gdprConsent.gdprApplies = false;
- result = spec.getUserSyncs({}, [{ body: videoResponse }], gdprConsent);
+ result = spec.getUserSyncs({}, [{body: videoResponse}], gdprConsent, 'cleanmediaCCPA');
expect(result).to.be.an('array');
expect(result.length).to.equal(1);
expect(result[0].type).to.equal('image');
- expect(result[0].url).to.equal(
- 'https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gc=missing'
- );
+ expect(result[0].url).to.equal('https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gdpr=0&consent=&us_privacy=cleanmediaCCPA');
- videoResponse.ext.utrk[0].url =
- 'https://bidder.cleanmediaads.com/pix/1275/scm';
- result = spec.getUserSyncs({}, [{ body: videoResponse }], gdprConsent);
+ videoResponse.ext.utrk[0].url = 'https://bidder.cleanmediaads.com/pix/1275/scm';
+ result = spec.getUserSyncs({}, [{body: videoResponse}], gdprConsent);
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal('https://bidder.cleanmediaads.com/pix/1275/scm');
+ });
+
+ it('validates existence of gdpr, gdpr consent and usp consent', () => {
+ let result = spec.getUserSyncs({}, [{body: videoResponse}], gdprConsent, 'cleanmediaCCPA');
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal('https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gdpr=1&consent=consent%20string&us_privacy=cleanmediaCCPA');
+
+ gdprConsent.gdprApplies = false;
+ result = spec.getUserSyncs({}, [{body: videoResponse}], gdprConsent, '');
expect(result).to.be.an('array');
expect(result.length).to.equal(1);
expect(result[0].type).to.equal('image');
- expect(result[0].url).to.equal(
- 'https://bidder.cleanmediaads.com/pix/1275/scm?gc=missing'
- );
+ expect(result[0].url).to.equal('https://bidder.cleanmediaads.com/pix/1275/scm?cb=1545900621675&gdpr=0&consent=&us_privacy=');
});
});
});