diff --git a/.travis.yml b/.travis.yml index 917b119c05c..8addbe93b94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,21 @@ +sudo: required +dist: trusty + language: node_js node_js: - "5.1" +addons: + apt: + sources: + - google-chrome + packages: + - google-chrome-stable + before_install: - npm install -g gulp - - export CHROME_BIN=chromium-browser + - export CHROME_BIN=google-chrome - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start diff --git a/adapters.json b/adapters.json index dd928df7c95..dc7796ea482 100644 --- a/adapters.json +++ b/adapters.json @@ -1,23 +1,27 @@ [ "aardvark", "adblade", + "adbund", "adbutler", "adequant", "adform", "adkernel", "admedia", + "vertamedia", "aol", "appnexus", "appnexusAst", "conversant", "districtmDMX", "fidelity", - "getintent", "gumgum", "hiromedia", "indexExchange", "kruxlink", + "getintent", "komoona", + "lifestreet", + "mantis", "openx", "piximedia", "pubmatic", @@ -30,7 +34,10 @@ "sonobi", "sovrn", "springserve", + "thoughtleadr", + "stickyadstv", "triplelift", + "twenga", "yieldbot", "nginad", "brightcom", @@ -65,21 +72,41 @@ "appnexusAst": { "supportedMediaTypes": ["video"] } + }, { + "vertamedia": { + "supportedMediaTypes": ["video"] + } + }, + { + "appnexus": { + "alias": "matomy" + } }, { "rubicon": { - "alias": "rubiconLite" + "alias": "rubiconLite", + "supportedMediaTypes": ["video"] } }, { "appnexus": { "alias": "featureforward" } + }, + { + "appnexus": { + "alias": "oftmedia" + } }, { "adkernel": { "alias": "headbidding" } + }, + { + "getintent": { + "supportedMediaTypes" : ["video"] + } } ] diff --git a/browsers.json b/browsers.json index d220f9a0014..85bbc6b10b0 100644 --- a/browsers.json +++ b/browsers.json @@ -119,6 +119,14 @@ "device": null, "os": "Windows" }, + "bs_chrome_56_mac_sierra": { + "base": "BrowserStack", + "os": "OS X", + "os_version": "Sierra", + "browser": "chrome", + "device": null, + "browser_version": "56.0" + }, "bs_safari_9.1_mac_elcapitan": { "base": "BrowserStack", "os_version": "El Capitan", diff --git a/gulpHelpers.js b/gulpHelpers.js index 342cd04dbb8..6091dc4c495 100644 --- a/gulpHelpers.js +++ b/gulpHelpers.js @@ -53,10 +53,10 @@ module.exports = { createEnd2EndTestReport : function(targetDestinationDir) { var browsers = require('./browsers.json'); - var env = ['default']; + var env = []; var input = 'bs'; for(var key in browsers) { - if(key.substring(0, input.length) === input) { + if(key.substring(0, input.length) === input && browsers[key].browser !== 'iphone') { env.push(key); } } diff --git a/gulpfile.js b/gulpfile.js index 6d60a8809b8..d343068d165 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -21,6 +21,7 @@ var header = require('gulp-header'); var zip = require('gulp-zip'); var replace = require('gulp-replace'); var shell = require('gulp-shell'); +var optimizejs = require('gulp-optimize-js'); var CI_MODE = process.env.NODE_ENV === 'ci'; var prebid = require('./package.json'); @@ -73,6 +74,7 @@ gulp.task('webpack', function () { .pipe(replace('$prebid.version$', prebid.version)) .pipe(uglify()) .pipe(header(banner, { prebid: prebid })) + .pipe(optimizejs()) .pipe(gulp.dest('build/dist')) .pipe(connect.reload()); }); @@ -219,45 +221,46 @@ gulp.task('docs', ['clean-docs'], function () { }); gulp.task('e2etest', function() { - var cmd = '--env default'; + var cmdQueue = []; if(argv.browserstack) { var browsers = require('./browsers.json'); - var env = []; - var input = 'bs'; - for(var key in browsers) { - if(key.substring(0, input.length) === input) { - env.push(key); - } + delete browsers['bs_ie_9_windows_7']; + + var cmdStr = ' --config nightwatch.conf.js'; + if (argv.group) { + cmdStr = cmdStr + ' --group ' + argv.group; } - cmd = '--env default,' + env.join(','); - } + cmdStr = cmdStr + ' --reporter ./test/spec/e2e/custom-reporter/pbjs-html-reporter.js'; - if(argv.browserstack) { - cmd = cmd + ' --config nightwatch.conf.js'; - } else { - cmd = cmd + ' --config nightwatch.json'; - } + var startWith = 'bs'; - if (argv.group) { - cmd = cmd + ' --group ' + argv.group; + Object.keys(browsers).filter(function(v){ + return v.substring(0, startWith.length) === startWith && browsers[v].browser !== 'iphone'; + }).map(function(v,i,arr) { + var newArr = (i%2 === 0) ? arr.slice(i,i+2) : null; + if(newArr) { + var cmd = 'nightwatch --env ' + newArr.join(',') + cmdStr; + cmdQueue.push(cmd); + } + }); } - cmd = cmd + ' --reporter ./test/spec/e2e/custom-reporter/pbjs-html-reporter.js'; return gulp.src('') - .pipe(shell('nightwatch ' + cmd)); + .pipe(shell(cmdQueue.join(';'))); }); gulp.task('e2etest-report', function() { + var reportPort = 9010; var targetDestinationDir = './e2etest-report'; helpers.createEnd2EndTestReport(targetDestinationDir); connect.server({ - port: port, + port: reportPort, root: './', livereload: true }); setTimeout(function() { - opens('http://localhost:' + port + '/' + targetDestinationDir.slice(2) + '/results.html'); + opens('http://localhost:' + reportPort + '/' + targetDestinationDir.slice(2) + '/results.html'); }, 5000); }); diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html index f38d6dfc13b..19f4e6cc8a0 100644 --- a/integrationExamples/gpt/pbjs_example_gpt.html +++ b/integrationExamples/gpt/pbjs_example_gpt.html @@ -201,14 +201,14 @@ { bidder: 'memeglobal', params: { - tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com + tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com } }, { bidder: 'adblade', params: { partnerId: 42980, - bidfloor: 0.01 // OPTIONAL float bid floor in $ CPM + bidfloor: 0.01 // OPTIONAL float bid floor in $ CPM } }, { @@ -231,6 +231,13 @@ cur: 'EUR' } }, + { + bidder: 'adbund', + params: { + sid: '110238', // REQUIRED int. To get one, sign up http://www.adbund.com + bidfloor: 0.036 // OPTIONAL float bid floor in $ CPM + } + }, { bidder: 'smartyads', params: { @@ -326,22 +333,22 @@ } }, { - bidder: 'wideorbit', + bidder: 'memeglobal', params: { - pbId: 123, // REQUIRED Publisher Id, - pId: 123456 // REQUIRED Placement Id + tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com } }, { - bidder: 'memeglobal', + bidder: 'gumgum', params: { - tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com + inScreen: 'ggumtest' // REQUIRED str Tracking Id } }, { - bidder: 'gumgum', + bidder: 'wideorbit', params: { - inScreen: 'ggumtest' // REQUIRED str Tracking Id + pbId: 123, // REQUIRED Publisher Id, + pId: 123456 // REQUIRED Placement Id } } ] @@ -352,7 +359,7 @@ $$PREBID_GLOBAL$$.addAdUnits(adUnits); //register a callback handler - $$PREBID_GLOBAL$$.addCallback('adUnitBidsBack', function (adUnitCode) { + $$PREBID_GLOBAL$$.addCallback('adUnitBidsBack', function (adUnitCode) { console.debug('ad unit bids back for:', adUnitCode); }); diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html new file mode 100644 index 00000000000..68120e0e863 --- /dev/null +++ b/integrationExamples/gpt/x-domain/creative.html @@ -0,0 +1,72 @@ + diff --git a/integrationExamples/gpt/x-domain/creative.js b/integrationExamples/gpt/x-domain/creative.js deleted file mode 100644 index 787b67f928b..00000000000 --- a/integrationExamples/gpt/x-domain/creative.js +++ /dev/null @@ -1,56 +0,0 @@ -// this script can be returned by an ad server delivering a cross domain iframe, into which the -// creative will be rendered, e.g. DFP delivering a SafeFrame - -// set these domains as fits your environment and ensure matching protocols -// alternatively this can be passed as a macro on the query string of the ad server call, for -// example `%%PUBLISHER_DOMAIN%%`. -const publisherDomain = 'http://localhost:9999'; -const adServerDomain = 'http://tpc.googlesyndication.com'; - -function renderAd(ev) { - var key = ev.message ? 'message' : 'data'; - var adObject = {}; - try { - adObject = JSON.parse(ev[key]); - } catch (e) { - return; - } - - if (adObject.ad || adObject.adUrl) { - var doc = window.document; - var ad = adObject.ad; - var url = adObject.adUrl; - var width = adObject.width; - var height = adObject.height; - - if (adObject.mediaType === 'video') { - console.log('Error trying to write ad.'); - } else - - if (ad) { - doc.write(ad); - doc.close(); - } else if (url) { - doc.write(''); - doc.close(); - } else { - console.log('Error trying to write ad. No ad for bid response id: ' + id); - } - } - } - -function requestAdFromPrebid() { - var message = JSON.stringify({ - message: 'Prebid Request', - adId: '%%PATTERN:hb_adid%%', - adServerDomain - }); - window.parent.postMessage(message, publisherDomain); -} - -function listenAdFromPrebid() { - window.addEventListener('message', renderAd, false); -} - -listenAdFromPrebid(); -requestAdFromPrebid(); diff --git a/nightwatch.conf.js b/nightwatch.conf.js index c0583fee4df..072114953fe 100644 --- a/nightwatch.conf.js +++ b/nightwatch.conf.js @@ -1,17 +1,35 @@ module.exports = (function(settings) { var browsers = require('./browsers.json'); + delete browsers['bs_ie_9_windows_7']; + for(var browser in browsers) { + if(browsers[browser].browser === 'iphone') continue; + var desiredCapabilities = { "browserName": browsers[browser].browser, "version": browsers[browser].browser_version, - "platform": browsers[browser].os, + "platform": browsers[browser].os, "os": browsers[browser].os, - "os_version": browsers[browser].os_version, - "browser": browsers[browser].browser, - "browser_version": browsers[browser].browser_version, + "os_version": browsers[browser].os_version, + "browser": browsers[browser].browser, + "browser_version": browsers[browser].browser_version, }; - settings.test_settings[browser] = {} + settings.test_settings[browser] = { + "silent": true, + "exclude":["custom-assertions","custom-commands","common","custom-reporter"], + "screenshots" : { + "enabled" : false, + "path" : "" + }, + "javascriptEnabled": true, + "acceptSslCerts": true, + "browserstack.local": true, + "browserstack.debug": true, + "browserstack.selenium_version" : "2.53.0", + "browserstack.user": "${BROWSERSTACK_USERNAME}", + "browserstack.key": "${BROWSERSTACK_KEY}" + }; settings.test_settings[browser]['desiredCapabilities'] = desiredCapabilities; } return settings; diff --git a/package.json b/package.json index ec6ea57e99c..baa1291af12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "0.18.0", + "version": "0.21.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { @@ -23,9 +23,9 @@ "devDependencies": { "babel-core": "^6.5.2", "babel-loader": "^6.2.3", - "babel-plugin-transform-object-assign": "^6.8.0", - "babel-plugin-transform-es3-property-literals": "^6.8.0", "babel-plugin-transform-es3-member-expression-literals": "^6.8.0", + "babel-plugin-transform-es3-property-literals": "^6.8.0", + "babel-plugin-transform-object-assign": "^6.8.0", "babel-preset-es2015": "^6.5.0", "block-loader": "^2.1.0", "chai": "^3.3.0", @@ -46,6 +46,7 @@ "gulp-jshint": "^1.8.4", "gulp-karma": "0.0.4", "gulp-mocha": "^2.2.0", + "gulp-optimize-js": "^1.1.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.4.0", "gulp-shell": "^0.5.2", @@ -96,5 +97,8 @@ "webpack-stream": "^3.1.0", "yargs": "^1.3.1" }, - "dependencies": {} + "dependencies": { + "array-includes": "^3.0.2", + "array.prototype.find": "^2.0.3" + } } diff --git a/src/adaptermanager.js b/src/adaptermanager.js index 4c8ae95b3f7..69d7df404f3 100644 --- a/src/adaptermanager.js +++ b/src/adaptermanager.js @@ -26,7 +26,7 @@ function getBids({bidderCode, requestId, bidderRequestId, adUnits}) { } sizes = sizeMapping; } - return Object.assign(bid, { + return Object.assign({}, bid, { placementCode: adUnit.code, mediaType: adUnit.mediaType, sizes: sizes, diff --git a/src/adapters/adbund.js b/src/adapters/adbund.js new file mode 100644 index 00000000000..74809aa5e04 --- /dev/null +++ b/src/adapters/adbund.js @@ -0,0 +1,66 @@ +var CONSTANTS = require('../constants.json'); +var utils = require('../utils.js'); +var bidfactory = require('../bidfactory.js'); +var bidmanager = require('../bidmanager.js'); +var adloader = require('../adloader'); + +var adBundAdapter = function adBundAdapter() { + var timezone = (new Date()).getTimezoneOffset(); + var bidAPIs = [ + 'http://us-east-engine.adbund.xyz/prebid/ad/get', + 'http://us-west-engine.adbund.xyz/prebid/ad/get' + ]; + //Based on the time zone to select the interface to the server + var bidAPI = bidAPIs[timezone < 0 ? 0 : 1]; + + function _stringify(param) { + var result = []; + var key; + for (key in param) { + if (param.hasOwnProperty(key)) { + result.push(key + '=' + encodeURIComponent(param[key])); + } + } + return result.join('&'); + } + + function _createCallback(bid) { + return function (data) { + var response; + if (data && data.cpm) { + response = bidfactory.createBid(CONSTANTS.STATUS.GOOD); + response.bidderCode = 'adbund'; + Object.assign(response, data); + } else { + response = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); + response.bidderCode = 'adbund'; + } + bidmanager.addBidResponse(bid.placementCode, response); + }; + } + + function _requestBids(bid) { + var info = { + referrer: utils.getTopWindowUrl(), + domain: utils.getTopWindowLocation().hostname, + ua: window.navigator.userAgent + }; + var param = Object.assign({}, bid.params, info); + param.sizes = JSON.stringify(param.sizes || bid.sizes); + param.callback = '$$PREBID_GLOBAL$$.adbundResponse'; + $$PREBID_GLOBAL$$.adbundResponse = _createCallback(bid); + adloader.loadScript(bidAPI + '?' + _stringify(param)); + } + + function _callBids(params) { + (params.bids || []).forEach(function (bid) { + _requestBids(bid); + }); + } + + return { + callBids: _callBids + }; +}; + +module.exports = adBundAdapter; \ No newline at end of file diff --git a/src/adapters/adform.js b/src/adapters/adform.js index 61b013315f8..705e91591f4 100644 --- a/src/adapters/adform.js +++ b/src/adapters/adform.js @@ -2,6 +2,7 @@ var utils = require('../utils.js'); var adloader = require('../adloader.js'); var bidmanager = require('../bidmanager.js'); var bidfactory = require('../bidfactory.js'); +var STATUSCODES = require('../constants.json').STATUS; function AdformAdapter() { @@ -70,7 +71,7 @@ function AdformAdapter() { if (adItem && adItem.response === 'banner' && verifySize(adItem, bid.sizes)) { - bidObject = bidfactory.createBid(1); + bidObject = bidfactory.createBid(STATUSCODES.GOOD, bid); bidObject.bidderCode = bidder; bidObject.cpm = adItem.win_bid; bidObject.cur = adItem.win_cur; @@ -80,7 +81,7 @@ function AdformAdapter() { bidObject.dealId = adItem.deal_id; bidmanager.addBidResponse(bid.placementCode, bidObject); } else { - bidObject = bidfactory.createBid(2); + bidObject = bidfactory.createBid(STATUSCODES.NO_BID, bid); bidObject.bidderCode = bidder; bidmanager.addBidResponse(bid.placementCode, bidObject); } diff --git a/src/adapters/adkernel.js b/src/adapters/adkernel.js index a78416999c2..b3383f44e9b 100644 --- a/src/adapters/adkernel.js +++ b/src/adapters/adkernel.js @@ -26,6 +26,7 @@ const AdKernelAdapter = function AdKernelAdapter() { const _dispatch = {}; const originalBids = {}; const site = createSite(); + const syncedHostZones = {}; //translate adunit info into rtb impression dispatched by host/zone this.addImp = function (bid) { @@ -48,16 +49,34 @@ const AdKernelAdapter = function AdKernelAdapter() { //save rtb impression for specified ad-network host and zone _dispatch[host][zone].push(imp); originalBids[bidId] = bid; + //perform user-sync + if (!(host in syncedHostZones)){ + syncedHostZones[host] = []; + } + if (syncedHostZones[host].indexOf(zone) === -1) { + syncedHostZones[host].push(zone); + insertUserSync(host, zone); + } }; + function insertUserSync(host, zone) { + var iframe = utils.createInvisibleIframe(); + iframe.src = `//${host}/user-sync?zone=${zone}`; + try { + document.body.appendChild(iframe); + } catch (error) { + utils.logError(error); + } + } + /** * Main function to get bid requests */ this.dispatch = function (callback) { utils._each(_dispatch, (zones, host) => { - utils.logMessage('processing network ' + host); + utils.logMessage(`processing network ${host}`); utils._each(zones, (impressions, zone) => { - utils.logMessage('processing zone ' + zone); + utils.logMessage(`processing zone ${zone}`); dispatchRtbRequest(host, zone, impressions, callback); }); }); @@ -106,7 +125,7 @@ const AdKernelAdapter = function AdKernelAdapter() { * Build ad-network specific endpoint url */ function buildEndpointUrl(host) { - return window.location.protocol + '//' + host + '/rtbg'; + return `${window.location.protocol}//${host}/rtbg`; } function buildRequestParams(zone, rtbReq) { @@ -134,7 +153,7 @@ const AdKernelAdapter = function AdKernelAdapter() { //process individual bids utils._each(bids, (bid) => { if (!validateBidParams(bid.params)) { - utils.logError('Incorrect configuration for adkernel bidder:', bid.params); + utils.logError(`Incorrect configuration for adkernel bidder: ${bid.params}`); bidmanager.addBidResponse(bid.placementCode, createEmptyBidObject(bid)); } else { dispatcher.addImp(bid); @@ -144,10 +163,10 @@ const AdKernelAdapter = function AdKernelAdapter() { dispatcher.dispatch((bid, imp, bidResp) => { let adUnitId = bid.placementCode; if (bidResp) { - utils.logMessage('got response for ' + adUnitId); + utils.logMessage(`got response for ${adUnitId}`); bidmanager.addBidResponse(adUnitId, createBidObject(bidResp, bid, imp.banner.w, imp.banner.h)); } else { - utils.logMessage('got empty response for ' + adUnitId); + utils.logMessage(`got empty response for ${adUnitId}`); bidmanager.addBidResponse(adUnitId, createEmptyBidObject(bid)); } }); diff --git a/src/adapters/appnexusAst.js b/src/adapters/appnexusAst.js index 67cc393bba7..3258eeb7821 100644 --- a/src/adapters/appnexusAst.js +++ b/src/adapters/appnexusAst.js @@ -27,6 +27,7 @@ function AppnexusAstAdapter() { baseAdapter.callBids = function(bidRequest) { const bids = bidRequest.bids || []; var member = 0; + let userObj; const tags = bids .filter(bid => valid(bid)) .map(bid => { @@ -39,7 +40,7 @@ function AppnexusAstAdapter() { tag.uuid = bid.bidId; if(bid.params.placementId) { tag.id = parseInt(bid.params.placementId, 10); - } else { + } else { tag.code = bid.params.invCode; } tag.allow_smaller_sizes = bid.params.allowSmallerSizes || false; @@ -84,17 +85,17 @@ function AppnexusAstAdapter() { } if (bid.params.user) { - tag.user = {}; + userObj = {}; Object.keys(bid.params.user) .filter(param => USER_PARAMS.includes(param)) - .forEach(param => tag.user[param] = bid.params.user[param]); + .forEach(param => userObj[param] = bid.params.user[param]); } return tag; }); if (!utils.isEmpty(tags)) { - const payloadJson = {tags: [...tags]}; + const payloadJson = {tags: [...tags], user: userObj}; if (member > 0) { payloadJson.member_id = member; } @@ -239,6 +240,7 @@ function AppnexusAstAdapter() { bid.width = ad.rtb.video.player_width; bid.height = ad.rtb.video.player_height; bid.vastUrl = ad.rtb.video.asset_url; + bid.descriptionUrl = ad.rtb.video.asset_url; } else { bid.width = ad.rtb.banner.width; bid.height = ad.rtb.banner.height; diff --git a/src/adapters/brightcom.js b/src/adapters/brightcom.js index 1040df3b990..9df4a872d47 100644 --- a/src/adapters/brightcom.js +++ b/src/adapters/brightcom.js @@ -112,7 +112,7 @@ var BrightcomAdapter = function BrightcomAdapter() { // Define the bid request call URL var bidRequestCallUrl = 'https://' + brightcomUrl + - '?callback=' + brightcomCallbackFunction + + '?callback=' + encodeURIComponent(brightcomCallbackFunction) + '&request=' + encodeURIComponent(JSON.stringify(brightcomBidReq)); // Add the call to get the bid diff --git a/src/adapters/centro.js b/src/adapters/centro.js index 7e7dc100c77..cad9dc7713b 100644 --- a/src/adapters/centro.js +++ b/src/adapters/centro.js @@ -39,12 +39,10 @@ var CentroAdapter = function CentroAdapter() { utils.logError(LOG_ERROR_MESS.noUnit, bidderCode); return; } - var query = ['s=' + bid.unit];//,'url=www.abc15.com','sz=320x50']; + var query = ['s=' + bid.unit, 'adapter=prebid'];//,'url=www.abc15.com','sz=320x50']; var isDev = bid.unit.toString() === '28136'; - if (bid.page_url) { - query.push('url=' + encodeURIComponent(bid.page_url)); - } + query.push('url=' + encodeURIComponent(bid.page_url || location.href)); //check size format if ( size instanceof Array && @@ -55,7 +53,7 @@ var CentroAdapter = function CentroAdapter() { query.push('sz=' + size.join('x')); } //make handler name for JSONP request - var handlerName = handlerPrefix + bid.unit + size.join('x'); + var handlerName = handlerPrefix + bid.unit + size.join('x') + encodeURIComponent(placementCode); query.push('callback=' + handlerName); //maybe is needed add some random parameter to disable cache @@ -77,7 +75,7 @@ var CentroAdapter = function CentroAdapter() { var bidObject; var bid = resp && resp.bid || resp; - if (bid && bid.adTag && bid.sectionID === unit) { + if (bid && bid.adTag && bid.sectionID && bid.sectionID.toString() === unit.toString()) { bidObject = bidfactory.createBid(1); bidObject.cpm = bid.value; bidObject.ad = bid.adTag; diff --git a/src/adapters/getintent.js b/src/adapters/getintent.js index 1293d98f903..a98fab952ae 100644 --- a/src/adapters/getintent.js +++ b/src/adapters/getintent.js @@ -1,5 +1,7 @@ /*jshint loopfunc: true */ +import { STATUS } from 'src/constants'; + var bidfactory = require('../bidfactory.js'); var bidmanager = require('../bidmanager.js'); var adloader = require('../adloader.js'); @@ -33,25 +35,34 @@ var GetIntentAdapter = function GetIntentAdapter() { pid: bidRequest.params.pid, // required tid: bidRequest.params.tid, // required known: bidRequest.params.known || 1, + is_video: bidRequest.mediaType === 'video', + video: bidRequest.params.video || {}, size: bidRequest.sizes[0].join("x"), }; addOptional(bidRequest.params, request, ['cur', 'floor']); - window.gi_hb.makeBid(request, function(bidResponse) { - if (bidResponse.no_bid === 1) { - var nobid = bidfactory.createBid(2); - nobid.bidderCode = bidRequest.bidder; - bidmanager.addBidResponse(bidRequest.placementCode, nobid); - } else { - var size = bidResponse.size.split('x'); - var bid = bidfactory.createBid(1); - bid.bidderCode = bidRequest.bidder; - bid.cpm = bidResponse.cpm; - bid.ad = bidResponse.ad; - bid.width = size[0]; - bid.height = size[1]; - bidmanager.addBidResponse(bidRequest.placementCode, bid); - } - }); + (function (r, br) { + window.gi_hb.makeBid(r, function(bidResponse) { + if (bidResponse.no_bid === 1) { + var nobid = bidfactory.createBid(STATUS.NO_BID); + nobid.bidderCode = br.bidder; + bidmanager.addBidResponse(br.placementCode, nobid); + } else { + var bid = bidfactory.createBid(STATUS.GOOD); + var size = bidResponse.size.split('x'); + bid.bidderCode = br.bidder; + bid.cpm = bidResponse.cpm; + bid.width = size[0]; + bid.height = size[1]; + if (br.mediaType === 'video') { + bid.vastUrl = bidResponse.vast_url; + bid.descriptionUrl = bidResponse.vast_url; + } else { + bid.ad = bidResponse.ad; + } + bidmanager.addBidResponse(br.placementCode, bid); + } + }); + })(request, bidRequest); } } diff --git a/src/adapters/gumgum.js b/src/adapters/gumgum.js index 7434444d570..d9a08d96b97 100644 --- a/src/adapters/gumgum.js +++ b/src/adapters/gumgum.js @@ -13,6 +13,9 @@ const GumgumAdapter = function GumgumAdapter() { let topWindow; let topScreen; let pageViewId; + const requestCache = {}; + const throttleTable = {}; + const defaultThrottle = 3e4; try { topWindow = global.top; @@ -21,6 +24,10 @@ const GumgumAdapter = function GumgumAdapter() { return utils.logError(error); } + function _getTimeStamp() { + return new Date().getTime(); + } + function _callBids({ bids }) { const browserParams = { vw: topWindow.innerWidth, @@ -36,6 +43,7 @@ const GumgumAdapter = function GumgumAdapter() { , params = {} , placementCode } = bidRequest; + const timestamp = _getTimeStamp(); const trackingId = params.inScreen; const nativeId = params.native; const slotId = params.inSlot; @@ -52,6 +60,21 @@ const GumgumAdapter = function GumgumAdapter() { ', please check your implementation.' ); } + + /* throttle based on the latest request for this product */ + const productId = bid.pi; + const requestKey = productId + '|' + placementCode; + const throttle = throttleTable[productId]; + const latestRequest = requestCache[requestKey]; + if (latestRequest && throttle && (timestamp - latestRequest) < throttle) { + return utils.logWarn( + `[GumGum] The refreshes for "${ placementCode }" with the params ` + + `${ JSON.stringify(params) } should be at least ${ throttle / 1e3 }s apart.` + ); + } + /* update the last request */ + requestCache[requestKey] = timestamp; + /* tracking id is required for in-image and in-screen */ if (trackingId) bid.t = trackingId; /* native ads require a native placement id */ @@ -75,26 +98,30 @@ const GumgumAdapter = function GumgumAdapter() { }); } - const _handleGumGumResponse = cachedBidRequest => bidResponse => { - const ad = bidResponse && bidResponse.ad; - const pag = bidResponse && bidResponse.pag; + const _handleGumGumResponse = cachedBidRequest => (bidResponse = {}) => { + const { pi: productId + } = cachedBidRequest; + const { ad = {} + , pag = {} + , thms: throttle + } = bidResponse; /* cache the pageViewId */ if (pag && pag.pvid) pageViewId = pag.pvid; - /* create the bid */ if (ad && ad.id) { + /* set the new throttle */ + throttleTable[productId] = throttle || defaultThrottle; + /* create the bid */ const bid = bidfactory.createBid(1); const { t: trackingId - , pi: productId - , placementCode - } = cachedBidRequest; - bidResponse.placementCode = placementCode; + } = pag; + bidResponse.request = cachedBidRequest; const encodedResponse = encodeURIComponent(JSON.stringify(bidResponse)); const gumgumAdLoader = ` + `; + } + return null; + } + + return { + callBids: _callBids + }; +}; + +module.exports = LifestreetAdapter; \ No newline at end of file diff --git a/src/adapters/mantis.js b/src/adapters/mantis.js new file mode 100644 index 00000000000..5b4b17f1638 --- /dev/null +++ b/src/adapters/mantis.js @@ -0,0 +1,223 @@ +var bidfactory = require('../bidfactory.js'); +var bidmanager = require('../bidmanager.js'); +var adloader = require('../adloader'); +var constants = require('../constants.json'); + +module.exports = function () { + function inIframe() { + try { + return window.self !== window.top && !window.mantis_link; + } catch (e) { + return true; + } + } + + function isDesktop(ignoreTouch) { + var scope = function (win) { + var width = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth; + var supportsTouch = !ignoreTouch && ('ontouchstart' in window || navigator.msMaxTouchPoints); + + return !supportsTouch && (!width || width >= (window.mantis_breakpoint || 768)); + }; + + if (inIframe()) { + try { + return scope(window.top); + } catch (ex) { + } + } + + return scope(window); + } + + function isSendable(val) { + if (val === null || val === undefined) { + return false; + } + + if (typeof val === 'string') { + return !(!val || /^\s*$/.test(val)); + } + + if (typeof val === 'number') { + return !isNaN(val); + } + + return true; + } + + function isObject(value) { + return Object.prototype.toString.call(value) === '[object Object]'; + } + + function isAmp() { + return typeof window.context === "object" && (window.context.tagName === "AMP-AD" || window.context.tagName === "AMP-EMBED"); + } + + function isSecure() { + return document.location.protocol === "https:"; + } + + function isArray(value) { + return Object.prototype.toString.call(value) === '[object Array]'; + } + + function jsonp(callback) { + if (!window.mantis_jsonp) { + window.mantis_jsonp = []; + } + + window.mantis_jsonp.push(callback); + + return 'mantis_jsonp[' + (window.mantis_jsonp.length - 1) + ']'; + } + + function jsonToQuery(data, chain, form) { + if (!data) { + return null; + } + + var parts = form || []; + + for (var key in data) { + var queryKey = key; + + if (chain) { + queryKey = chain + '[' + key + ']'; + } + + var val = data[key]; + + if (isArray(val)) { + for (var index = 0; index < val.length; index++) { + var akey = queryKey + '[' + index + ']'; + var aval = val[index]; + + if (isObject(aval)) { + jsonToQuery(aval, akey, parts); + } else if (isSendable(aval)) { + parts.push(akey + '=' + encodeURIComponent(aval)); + } + } + } else if (isObject(val)) { + jsonToQuery(val, queryKey, parts); + } else if (isSendable(val)) { + parts.push(queryKey + '=' + encodeURIComponent(val)); + } + } + + return parts.join('&'); + } + + + function buildMantisUrl(path, data, domain) { + var params = { + referrer: document.referrer, + tz: new Date().getTimezoneOffset(), + buster: new Date().getTime(), + secure: isSecure() + }; + + if (!inIframe() || isAmp()) { + params.mobile = !isAmp() && isDesktop(true) ? 'false' : 'true'; + } + + if (window.mantis_uuid) { + params.uuid = window.mantis_uuid; + } else if (window.localStorage) { + var localUuid = window.localStorage.getItem('mantis:uuid'); + + if (localUuid) { + params.uuid = localUuid; + } + } + + if (!inIframe()) { + try { + params.title = window.top.document.title; + params.referrer = window.top.document.referrer; + params.url = window.top.document.location.href; + } catch (ex) { + + } + } else { + params.iframe = true; + } + + if (isAmp()) { + if (!params.url && window.context.canonicalUrl) { + params.url = window.context.canonicalUrl; + } + + if (!params.url && window.context.location) { + params.url = window.context.location.href; + } + + if (!params.referrer && window.context.referrer) { + params.referrer = window.context.referrer; + } + } + + Object.keys(data || {}).forEach(function (key) { + params[key] = data[key]; + }); + + var query = jsonToQuery(params); + + return (window.mantis_domain === undefined ? domain || 'https://mantodea.mantisadnetwork.com' : window.mantis_domain) + path + '?' + query; + } + + var Prebid = function (bidfactory, bidmanager, adloader, constants) { + return { + callBids: function (params) { + var property = null; + + params.bids.some(function (bid) { + if (bid.params.property) { + property = bid.params.property; + + return true; + } + }); + + var url = { + jsonp: jsonp(function (resp) { + params.bids.forEach(function (bid) { + var ad = resp.ads[bid.bidId]; + + var bidObject; + + if (ad) { + bidObject = bidfactory.createBid(constants.STATUS.GOOD); + bidObject.bidderCode = 'mantis'; + bidObject.cpm = ad.cpm; + bidObject.ad = ad.html; + bidObject.width = ad.width; + bidObject.height = ad.height; + } else { + bidObject = bidfactory.createBid(constants.STATUS.NO_BID); + bidObject.bidderCode = 'mantis'; + } + + bidmanager.addBidResponse(bid.placementCode, bidObject); + }); + }), + property: property, + bids: params.bids.map(function (bid) { + return { + bidId: bid.bidId, + sizes: bid.sizes.map(function (size) { + return {width: size[0], height: size[1]}; + }) + }; + }), + version: 1 + }; + + adloader.loadScript(buildMantisUrl('/website/prebid', url)); + } + }; + }; + + return new Prebid(bidfactory, bidmanager, adloader, constants); +}; \ No newline at end of file diff --git a/src/adapters/memeglobal.js b/src/adapters/memeglobal.js index 82b6ad4cf11..9eb7f297d97 100644 --- a/src/adapters/memeglobal.js +++ b/src/adapters/memeglobal.js @@ -106,7 +106,7 @@ var MemeGlobalAdapter = function MemeGlobalAdapter() { bidResponse.placementCode = placementCode; bidResponse.size = bidRequested.sizes; var responseAd = bidderBid.adm; - var responseNurl = ''; + var responseNurl = ''; bidResponse.creative_id = bidderBid.id; bidResponse.bidderCode = bidderName; bidResponse.cpm = responseCPM; diff --git a/src/adapters/openx.js b/src/adapters/openx.js index fe889cd9d78..21c5ba3476d 100644 --- a/src/adapters/openx.js +++ b/src/adapters/openx.js @@ -43,18 +43,16 @@ const OpenxAdapter = function OpenxAdapter() { }; // no fill :( - if (!auid) { + if (!auid || !adUnit.pub_rev) { addBidResponse(null, bid); continue; } adUnit.used = true; - if (adUnit.pub_rev) { - beaconParams.br = beaconParams.bt < beaconParams.bd ? 't' : 'p'; - beaconParams.bp = adUnit.pub_rev; - beaconParams.ts = adUnit.ts; - addBidResponse(adUnit, bid); - } + beaconParams.br = beaconParams.bt < beaconParams.bd ? 't' : 'p'; + beaconParams.bp = adUnit.pub_rev; + beaconParams.ts = adUnit.ts; + addBidResponse(adUnit, bid); buildBoPixel(adUnit.creative[0], beaconParams); } }; diff --git a/src/adapters/pubmatic.js b/src/adapters/pubmatic.js index 434097e98c5..c039c4eac7a 100644 --- a/src/adapters/pubmatic.js +++ b/src/adapters/pubmatic.js @@ -118,7 +118,7 @@ var PubmaticAdapter = function PubmaticAdapter() { adResponse.adSlot = bid.adSlot; adResponse.cpm = Number(adUnitInfo.bid); adResponse.ad = unescape(adUnit.creative_tag); // jshint ignore:line - adResponse.ad += utils.createTrackPixelHtml(decodeURIComponent(adUnit.tracking_url)); + adResponse.ad += utils.createTrackPixelIframeHtml(decodeURIComponent(adUnit.tracking_url)); adResponse.width = dimensions[0]; adResponse.height = dimensions[1]; adResponse.dealId = adUnitInfo.wdeal; diff --git a/src/adapters/rhythmone.js b/src/adapters/rhythmone.js index b86d3aee4d3..77ab3e4cd13 100644 --- a/src/adapters/rhythmone.js +++ b/src/adapters/rhythmone.js @@ -261,6 +261,9 @@ module.exports = function(bidManager, global, loader){ bidParams = getBidParameters(params.bids); debug = (bidParams !== null && bidParams.debug === true); + + auctionEnded = false; + requestCompleted = false; track(debug, 'hb', 'callBids'); @@ -337,4 +340,4 @@ module.exports = function(bidManager, global, loader){ logToConsole("version: "+version); }; -}; \ No newline at end of file +}; diff --git a/src/adapters/rubicon.js b/src/adapters/rubicon.js index 8baccc2dd87..d9d884aa0dc 100644 --- a/src/adapters/rubicon.js +++ b/src/adapters/rubicon.js @@ -7,6 +7,17 @@ import { STATUS } from 'src/constants'; const RUBICON_BIDDER_CODE = 'rubicon'; +// use deferred function call since version isn't defined yet at this point +function getIntegration() { + return 'pbjs_lite_' + $$PREBID_GLOBAL$$.version; +} + +// use protocol relative urls for http or https +const FASTLANE_ENDPOINT = '//fastlane.rubiconproject.com/a/api/fastlane.json'; +const VIDEO_ENDPOINT = '//optimized-by-adv.rubiconproject.com/v1/auction/video'; + +const TIMEOUT_BUFFER = 500; + var sizeMap = { 1:'468x60', 2:'728x90', @@ -49,7 +60,12 @@ function RubiconAdapter() { bids.forEach(bid => { try { - ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true}); + // Video endpoint only accepts POST calls + if (bid.mediaType === 'video') { + ajax(VIDEO_ENDPOINT, bidCallback, buildVideoRequestPayload(bid, bidderRequest), {withCredentials: true}); + } else { + ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true}); + } } catch(err) { utils.logError('Error sending rubicon request for placement code ' + bid.placementCode, null, err); addErrorBid(); @@ -77,6 +93,82 @@ function RubiconAdapter() { }); } + function _getScreenResolution() { + return [window.screen.width, window.screen.height].join('x'); + } + + function buildVideoRequestPayload(bid, bidderRequest) { + bid.startTime = new Date().getTime(); + + let params = bid.params; + + if(!params || typeof params.video !== 'object') { + throw 'Invalid Video Bid'; + } + + let size; + if(params.video.playerWidth && params.video.playerHeight) { + size = [ + params.video.playerWidth, + params.video.playerHeight + ]; + } else if( + Array.isArray(bid.sizes) && bid.sizes.length > 0 && + Array.isArray(bid.sizes[0]) && bid.sizes[0].length > 1 + ) { + size = bid.sizes[0]; + } else { + throw "Invalid Video Bid - No size provided"; + } + + let postData = { + page_url: !params.referrer ? utils.getTopWindowUrl() : params.referrer, + resolution: _getScreenResolution(), + account_id: params.accountId, + integration: getIntegration(), + timeout: bidderRequest.timeout - (Date.now() - bidderRequest.auctionStart + TIMEOUT_BUFFER), + stash_creatives: true, + ae_pass_through_parameters: params.video.aeParams, + slots: [] + }; + + // Define the slot object + let slotData = { + site_id: params.siteId, + zone_id: params.zoneId, + position: params.position || 'btf', + floor: 0.01, + element_id: bid.placementCode, + name: bid.placementCode, + language: params.video.language, + width: size[0], + height: size[1] + }; + + // check and add inventory, keywords, visitor and size_id data + if(params.video.size_id) { + slotData.size_id = params.video.size_id; + } else { + throw "Invalid Video Bid - Invalid Ad Type!"; + } + + if(params.inventory && typeof params.inventory === 'object') { + slotData.inventory = params.inventory; + } + + if(params.keywords && Array.isArray(params.keywords)) { + slotData.keywords = params.keywords; + } + + if(params.visitor && typeof params.visitor === 'object') { + slotData.visitor = params.visitor; + } + + postData.slots.push(slotData); + + return(JSON.stringify(postData)); + } + function buildOptimizedCall(bid) { bid.startTime = new Date().getTime(); @@ -85,6 +177,7 @@ function RubiconAdapter() { siteId, zoneId, position, + floor, keywords, visitor, inventory, @@ -93,6 +186,7 @@ function RubiconAdapter() { } = bid.params; // defaults + floor = (floor = parseFloat(floor)) > 0.01 ? floor : 0.01; position = position || 'btf'; // use rubicon sizes if provided, otherwise adUnit.sizes @@ -112,9 +206,9 @@ function RubiconAdapter() { 'size_id', parsedSizes[0], 'alt_size_ids', parsedSizes.slice(1).join(',') || undefined, 'p_pos', position, - 'rp_floor', '0.01', - 'tk_flint', 'pbjs.lite', - 'p_screen_res', window.screen.width +'x'+ window.screen.height, + 'rp_floor', floor, + 'tk_flint', getIntegration(), + 'p_screen_res', _getScreenResolution(), 'kw', keywords, 'tk_user_key', userId ]; @@ -136,7 +230,7 @@ function RubiconAdapter() { (memo, curr, index) => index % 2 === 0 && queryString[index + 1] !== undefined ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, - '//fastlane.rubiconproject.com/a/api/fastlane.json?' // use protocol relative link for http or https + FASTLANE_ENDPOINT + '?' ).slice(0, -1); // remove trailing & } @@ -151,23 +245,29 @@ function RubiconAdapter() { `; function handleRpCB(responseText, bidRequest) { - let responseObj = JSON.parse(responseText); // can throw + var responseObj = JSON.parse(responseText), // can throw + ads = responseObj.ads, + adResponseKey = bidRequest.placementCode; - if( - typeof responseObj !== 'object' || - responseObj.status !== 'ok' || - !Array.isArray(responseObj.ads) || - responseObj.ads.length < 1 - ) { + // check overall response + if(typeof responseObj !== 'object' || responseObj.status !== 'ok') { throw 'bad response'; } - var ads = responseObj.ads; + // video ads array is wrapped in an object + if (bidRequest.mediaType === 'video' && typeof ads === 'object') { + ads = ads[adResponseKey]; + } + + // check the ad response + if(!Array.isArray(ads) || ads.length < 1) { + throw 'invalid ad response'; + } // if there are multiple ads, sort by CPM ads = ads.sort(_adCpmSort); - ads.forEach(function (ad) { + ads.forEach(ad => { if(ad.status !== 'ok') { throw 'bad ad status'; } @@ -178,9 +278,18 @@ function RubiconAdapter() { bid.creative_id = ad.ad_id; bid.bidderCode = bidRequest.bidder; bid.cpm = ad.cpm || 0; - bid.ad = _renderCreative(ad.script, ad.impression_id); - [bid.width, bid.height] = sizeMap[ad.size_id].split('x').map(num => Number(num)); bid.dealId = ad.deal; + if (bidRequest.mediaType === 'video') { + bid.width = bidRequest.params.video.playerWidth; + bid.height = bidRequest.params.video.playerHeight; + bid.vastUrl = ad.creative_depot_url; + bid.descriptionUrl = ad.impression_id; + bid.impression_id = ad.impression_id; + } else { + bid.ad = _renderCreative(ad.script, ad.impression_id); + [bid.width, bid.height] = sizeMap[ad.size_id].split('x').map(num => Number(num)); + } + try { bidmanager.addBidResponse(bidRequest.placementCode, bid); diff --git a/src/adapters/smartadserver.js b/src/adapters/smartadserver.js index 82498dd2787..f35923411bb 100644 --- a/src/adapters/smartadserver.js +++ b/src/adapters/smartadserver.js @@ -14,9 +14,11 @@ var SmartAdServer = function SmartAdServer() { bidObject = bidfactory.createBid(1); bidObject.bidderCode = 'smartadserver'; bidObject.cpm = adUnit.cpm; + bidObject.currency = adUnit.currency; bidObject.ad = adUnit.ad; bidObject.width = adUnit.width; bidObject.height = adUnit.height; + bidObject.dealId = adUnit.dealId; bidmanager.addBidResponse(bid.placementCode, bidObject); } else { utils.logMessage(`[SmartAdServer] no bid response for placementCode ${bid.placementCode}`); @@ -39,6 +41,7 @@ var SmartAdServer = function SmartAdServer() { "siteid": bid.params.siteId, "pgid": bid.params.pageId, "fmtid": bid.params.formatId, + "ccy": bid.params.currency || "USD", "tgt": encodeURIComponent(bid.params.target || ''), "tag": bid.placementCode, "sizes": bid.sizes.map(size => size[0] + "x" + size[1]).join(","), diff --git a/src/adapters/stickyadstv.js b/src/adapters/stickyadstv.js new file mode 100644 index 00000000000..803cd626d56 --- /dev/null +++ b/src/adapters/stickyadstv.js @@ -0,0 +1,292 @@ +var bidfactory = require('../bidfactory.js'); +var bidmanager = require('../bidmanager.js'); +var adloader = require('../adloader.js'); + +var StickyAdsTVAdapter = function StickyAdsTVAdapter() { + + var MUSTANG_URL = "//cdn.stickyadstv.com/mustang/mustang.min.js"; + var INTEXTROLL_URL = "//cdn.stickyadstv.com/prime-time/intext-roll.min.js"; + var SCREENROLL_URL = "//cdn.stickyadstv.com/prime-time/screen-roll.min.js"; + + var topMostWindow = getTopMostWindow(); + topMostWindow.stickyadstv_cache = {}; + + function _callBids(params) { + + var bids = params.bids || []; + for (var i = 0; i < bids.length; i++) { + var bid = bids[i]; + // Send out bid request for each bid given its tag IDs and query strings + + if(bid.placementCode && bid.params.zoneId) { + sendBidRequest(bid); + } + else { + console.warn("StickyAdsTV: Missing mandatory field(s)."); + } + + } + } + + function sendBidRequest(bid){ + + var placementCode = bid.placementCode; + + var integrationType = bid.params.format ? bid.params.format : "inbanner"; + var urltoLoad = MUSTANG_URL; + + if(integrationType === "intext-roll"){ + urltoLoad = INTEXTROLL_URL; + } + if(integrationType === "screen-roll"){ + urltoLoad = SCREENROLL_URL; + } + + var bidRegistered = false; + adloader.loadScript(urltoLoad, function(){ + + getBid(bid, function(bidObject){ + + if(!bidRegistered){ + bidRegistered = true; + bidmanager.addBidResponse(placementCode, bidObject); + } + + }); + }, true); + } + + function getBid(bid, callback){ + var zoneId = bid.params.zoneId || bid.params.zone; //accept both + var size = getBiggerSize(bid.sizes); + + var vastLoader = new window.com.stickyadstv.vast.VastLoader(); + bid.vast = topMostWindow.stickyadstv_cache[bid.placementCode] = vastLoader.getVast(); + + var vastCallback = { + onSuccess : bind(function(){ + + //'this' is the bid request here + var bidRequest = this; + + var adHtml = formatAdHTML(bidRequest,size); + var price = extractPrice(bidRequest.vast); + + callback(formatBidObject(bidRequest, true, price, adHtml, size[0], size[1])); + + },bid), + onError : bind(function(){ + var bidRequest = this; + callback(formatBidObject(bidRequest, false)); + },bid) + }; + + var config = { + zoneId:zoneId, + playerSize:size[0]+"x"+size[1], + vastUrlParams: bid.params.vastUrlParams, + componentId: "prebid-sticky"+(bid.params.format ? "-"+bid.params.format : "") + }; + + if(bid.params.format === "screen-roll"){ + //in screenroll case we never use the original div size. + config.playerSize = window.com.stickyadstv.screenroll.getPlayerSize(); + } + + vastLoader.load(config, vastCallback); + } + + function getBiggerSize(array){ + var result = [1,1]; + for(var i = 0; i< array.length; i++){ + if(array[i][0]*array[i][1] > result[0]*result[1]){ + result = array[i]; + } + } + return result; + } + + var formatInBannerHTML = function(bid,size){ + var placementCode = bid.placementCode; + + var divHtml = "
"; + + var script = ""; + + return divHtml+script; + }; + + var formatIntextHTML = function(bid){ + var placementCode = bid.placementCode; + + var config = bid.params; + + //default placement if no placement is set + if(!config.hasOwnProperty("domId") && !config.hasOwnProperty("auto") && !config.hasOwnProperty("p") && !config.hasOwnProperty("article")){ + config.domId = placementCode; + } + + var script = ""; + + return script; + }; + + var formatScreenRollHTML = function(bid){ + var placementCode = bid.placementCode; + + var config = bid.params; + + var script = ""; + + return script; + }; + + function formatAdHTML(bid, size){ + + var integrationType = bid.params.format; + + var html = ""; + if(integrationType === "intext-roll"){ + html = formatIntextHTML(bid); + } + else if(integrationType === "screen-roll"){ + html = formatScreenRollHTML(bid); + } + else { + html = formatInBannerHTML(bid,size); + } + + return html; + } + + + function extractPrice(vast){ + var priceData = vast.getPricing(); + + if(!priceData) { + console.warn("StickyAdsTV: Bid pricing Can't be retreived. You may need to enable pricing on you're zone. Please get in touch with your sticky contact."); + } + + return priceData; + } + + function formatBidObject(bidRequest, valid, priceData, html, width, height){ + var bidObject; + if(valid && priceData) { + // valid bid response + bidObject = bidfactory.createBid(1, bidRequest); + bidObject.bidderCode = 'stickyadstv'; + bidObject.cpm = priceData.price; + bidObject.currencyCode = priceData.currency; + bidObject.ad = html; + bidObject.width = width; + bidObject.height = height; + + } + else { + // invalid bid response + bidObject = bidfactory.createBid(2, bidRequest); + bidObject.bidderCode = 'stickyadstv'; + } + return bidObject; + } + + + /** + * returns the top most accessible window + */ + function getTopMostWindow(){ + var res=window; + + try { + while(top !== res){ + if(res.parent.location.href.length) + res=res.parent; + } + } + catch(e){} + + return res; + } + + /* Create a function bound to a given object (assigning `this`, and arguments, + * optionally). Binding with arguments is also known as `curry`. + * Delegates to **ECMAScript 5**'s native `Function.bind` if available. + * We check for `func.bind` first, to fail fast when `func` is undefined. + * + * @param {function} func + * @param {optional} context + * @param {...any} var_args + * @return {function} + */ + var bind = function(func, context) { + + return function() { + return func.apply(context,arguments); + }; + }; + + + // Export the callBids function, so that prebid.js can execute + // this function when the page asks to send out bid requests. + return { + callBids: _callBids, + formatBidObject: formatBidObject, + formatAdHTML: formatAdHTML, + getBiggerSize:getBiggerSize, + getBid:getBid, + getTopMostWindow:getTopMostWindow + }; +}; + +module.exports = StickyAdsTVAdapter; \ No newline at end of file diff --git a/src/adapters/thoughtleadr.js b/src/adapters/thoughtleadr.js new file mode 100644 index 00000000000..2237adb89f5 --- /dev/null +++ b/src/adapters/thoughtleadr.js @@ -0,0 +1,101 @@ +"use strict"; +var bidfactory = require("../bidfactory"); +var bidmanager = require("../bidmanager"); +var utils = require('../utils'); +var adloader_1 = require("../adloader"); +var ROOT_URL = "//cdn.thoughtleadr.com/v4/"; +var BID_AVAILABLE = 1; + +var ThoughtleadrAdapter = (function () { + function ThoughtleadrAdapter() { + } + + ThoughtleadrAdapter.prototype.callBids = function (params) { + if (!window.tldr || !window.tldr.requestPrebid) { + var rootUrl = ROOT_URL; + if (window.tldr && window.tldr.config && window.tldr.config.root_url) { + rootUrl = window.tldr.config.root_url; + } + adloader_1.loadScript(rootUrl + "page.js", this.handleBids.bind(this, params), true); + } + else { + this.handleBids(params); + } + }; + + ThoughtleadrAdapter.prototype.handleBids = function (params) { + var bids = (params.bids || []).filter(function (bid) { + return ThoughtleadrAdapter.valid(bid); + }); + + for (var _i = 0, bids_1 = bids; _i < bids_1.length; _i++) { + var bid = bids_1[_i]; + this.requestPlacement(bid); + } + }; + + ThoughtleadrAdapter.prototype.requestPlacement = function (bid) { + var _this = this; + var rid = utils.generateUUID(null); + var size = ThoughtleadrAdapter.getSizes(bid.sizes); + + window.tldr.requestPrebid(bid.params.placementId, rid).then(function (params) { + if (!params || !params.bid) { + utils.logError("invalid response from tldr.requestPrebid", undefined, undefined); + return; + } + + _this.receiver = function (ev) { + if (ev.origin === location.origin && + ev.data && ev.data.TLDR_REQUEST && ev.data.TLDR_REQUEST.rid === rid) { + ev.source.postMessage({TLDR_RESPONSE: {config: params.config, rid: rid}}, location.origin); + } + _this.stopListen(); + }; + window.addEventListener("message", _this.receiver, false); + setTimeout(function () { + return _this.stopListen(); + }, 5000); + + var bidObject; + if (params.bid.code === BID_AVAILABLE) { + bidObject = bidfactory.createBid(params.bid.code); + bidObject.bidderCode = 'thoughtleadr'; + bidObject.cpm = params.bid.cpm; + bidObject.ad = params.bid.ad; + bidObject.width = size.width; + bidObject.height = size.height; + } + else { + bidObject = bidfactory.createBid(params.bid.code); + bidObject.bidderCode = 'thoughtleadr'; + } + bidmanager.addBidResponse(bid.placementCode, bidObject); + }); + }; + + ThoughtleadrAdapter.prototype.stopListen = function () { + if (this.receiver) { + window.removeEventListener("message", this.receiver); + this.receiver = undefined; + } + }; + + ThoughtleadrAdapter.valid = function (bid) { + return !!(bid && bid.params && typeof bid.params.placementId === "string"); + }; + + ThoughtleadrAdapter.getSizes = function (sizes) { + var first = sizes[0]; + if (Array.isArray(first)) { + return ThoughtleadrAdapter.getSizes(first); + } + return { + width: sizes[0], + height: sizes[1] + }; + }; + return ThoughtleadrAdapter; +}()); + +module.exports = ThoughtleadrAdapter; diff --git a/src/adapters/twenga.js b/src/adapters/twenga.js new file mode 100644 index 00000000000..a7c844d7dd7 --- /dev/null +++ b/src/adapters/twenga.js @@ -0,0 +1,151 @@ +import { getBidRequest } from '../utils.js'; + +var CONSTANTS = require('../constants.json'); +var utils = require('../utils.js'); +var adloader = require('../adloader.js'); +var bidmanager = require('../bidmanager.js'); +var bidfactory = require('../bidfactory.js'); +var Adapter = require('./adapter.js'); + +var TwengaAdapter; +TwengaAdapter = function TwengaAdapter() { + var baseAdapter = Adapter.createNew('twenga'); + + baseAdapter.callBids = function (params) { + for (var i = 0; i < params.bids.length; i++) { + var bidRequest = params.bids[i]; + var callbackId = bidRequest.bidId; + adloader.loadScript(buildBidCall(bidRequest, callbackId)); + } + }; + + function buildBidCall(bid, callbackId) { + + var bidUrl = '//rtb.t.c4tw.net/Bid?'; + bidUrl = utils.tryAppendQueryString(bidUrl, 's', 'h'); + bidUrl = utils.tryAppendQueryString(bidUrl, 'callback', '$$PREBID_GLOBAL$$.handleTwCB'); + bidUrl = utils.tryAppendQueryString(bidUrl, 'callback_uid', callbackId); + bidUrl = utils.tryAppendQueryString(bidUrl, 'referrer', utils.getTopWindowUrl()); + if (bid.params) { + for (var key in bid.params) { + var value = bid.params[key]; + switch (key) { + case 'placementId': key = 'id'; break; + case 'siteId': key = 'sid'; break; + case 'publisherId': key = 'pid'; break; + case 'currency': key = 'cur'; break; + case 'bidFloor': key = 'min'; break; + case 'country': key = 'gz'; break; + } + bidUrl = utils.tryAppendQueryString(bidUrl, key, value); + } + } + + var sizes = utils.parseSizesInput(bid.sizes); + if (sizes.length > 0) { + bidUrl = utils.tryAppendQueryString(bidUrl, 'size', sizes.join(',')); + } + + bidUrl += 'ta=1'; + + // @if NODE_ENV='debug' + utils.logMessage('bid request built: ' + bidUrl); + + // @endif + + //append a timer here to track latency + bid.startTime = new Date().getTime(); + + return bidUrl; + } + + //expose the callback to the global object: + $$PREBID_GLOBAL$$.handleTwCB = function (bidResponseObj) { + + var bidCode; + + if (bidResponseObj && bidResponseObj.callback_uid) { + + var responseCPM; + var id = bidResponseObj.callback_uid; + var placementCode = ''; + var bidObj = getBidRequest(id); + if (bidObj) { + + bidCode = bidObj.bidder; + + placementCode = bidObj.placementCode; + + bidObj.status = CONSTANTS.STATUS.GOOD; + } + + // @if NODE_ENV='debug' + utils.logMessage('JSONP callback function called for ad ID: ' + id); + + // @endif + var bid = []; + if (bidResponseObj.result && + bidResponseObj.result.cpm && + bidResponseObj.result.cpm !== 0 && + bidResponseObj.result.ad) { + + var result = bidResponseObj.result; + + responseCPM = parseInt(result.cpm, 10); + + //CPM response from /Bid is dollar/cent multiplied by 10000 + //in order to avoid using floats + //switch CPM to "dollar/cent" + responseCPM = responseCPM / 10000; + + var ad = result.ad.replace('%%WP%%', result.cpm); + + //store bid response + //bid status is good (indicating 1) + bid = bidfactory.createBid(1, bidObj); + bid.creative_id = result.creative_id; + bid.bidderCode = bidCode; + bid.cpm = responseCPM; + if (ad && (ad.lastIndexOf('http', 0) === 0 || ad.lastIndexOf('//', 0) === 0)) + bid.adUrl = ad; + else + bid.ad = ad; + bid.width = result.width; + bid.height = result.height; + + bidmanager.addBidResponse(placementCode, bid); + + } else { + //no response data + // @if NODE_ENV='debug' + utils.logMessage('No prebid response from Twenga for placement code ' + placementCode); + + // @endif + //indicate that there is no bid for this placement + bid = bidfactory.createBid(2, bidObj); + bid.bidderCode = bidCode; + bidmanager.addBidResponse(placementCode, bid); + } + + } else { + //no response data + // @if NODE_ENV='debug' + utils.logMessage('No prebid response for placement %%PLACEMENT%%'); + + // @endif + } + }; + + return { + callBids: baseAdapter.callBids, + setBidderCode: baseAdapter.setBidderCode, + createNew: TwengaAdapter.createNew, + buildBidCall: buildBidCall + }; +}; + +TwengaAdapter.createNew = function () { + return new TwengaAdapter(); +}; + +module.exports = TwengaAdapter; diff --git a/src/adapters/vertamedia.js b/src/adapters/vertamedia.js new file mode 100644 index 00000000000..ea9e5402b09 --- /dev/null +++ b/src/adapters/vertamedia.js @@ -0,0 +1,101 @@ +import Adapter from 'src/adapters/adapter'; +import bidfactory from 'src/bidfactory'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import { ajax } from 'src/ajax'; +import { STATUS } from 'src/constants'; + +const ENDPOINT = '//rtb.vertamedia.com/hb/'; + +function VertamediaAdapter() { + var baseAdapter = Adapter.createNew('vertamedia'), + bidRequest; + + baseAdapter.callBids = function (bidRequests) { + if (!bidRequests || !bidRequests.bids || bidRequests.bids.length === 0) { + return; + } + + var RTBDataParams = prepareAndSaveRTBRequestParams(bidRequests.bids[0]); + + if (!RTBDataParams) { + return; + } + + ajax(ENDPOINT, handleResponse, RTBDataParams, { + contentType: 'text/plain', + withCredentials: true, + method: 'GET' + }); + }; + + function prepareAndSaveRTBRequestParams(bid) { + if (!bid || !bid.params || !bid.params.aid || !bid.placementCode) { + return; + } + + bidRequest = bid; + bidRequest.width = parseInt(bid.sizes[0], 10) || undefined; + bidRequest.height = parseInt(bid.sizes[1], 10) || undefined; + + return { + aid: bid.params.aid, + w: parseInt(bid.sizes[0], 10) || undefined, + h: parseInt(bid.sizes[1], 10) || undefined, + domain: document.location.hostname + }; + } + + /* Notify Prebid of bid responses so bids can get in the auction */ + function handleResponse(response) { + var parsed; + + try { + parsed = JSON.parse(response); + } catch (error) { + utils.logError(error); + } + + if (!parsed || parsed.error || !parsed.bids || !parsed.bids.length) { + bidmanager.addBidResponse(bidRequest.placementCode, createBid(STATUS.NO_BID)); + + return; + } + + bidmanager.addBidResponse(bidRequest.placementCode, createBid(STATUS.GOOD, parsed.bids[0])); + } + + function createBid(status, tag) { + var bid = bidfactory.createBid(status, tag); + + bid.code = baseAdapter.getBidderCode(); + bid.bidderCode = bidRequest.bidder; + + if (!tag || status !== STATUS.GOOD) { + return bid; + } + + bid.mediaType = 'video'; + bid.cpm = tag.cpm; + bid.creative_id = tag.cmpId; + bid.width = bidRequest.width; + bid.height = bidRequest.height; + bid.descriptionUrl = tag.url; + bid.vastUrl = tag.url; + + return bid; + } + + return { + createNew: VertamediaAdapter.createNew, + callBids: baseAdapter.callBids, + setBidderCode: baseAdapter.setBidderCode + }; + +} + +VertamediaAdapter.createNew = function () { + return new VertamediaAdapter(); +}; + +module.exports = VertamediaAdapter; diff --git a/src/adapters/wideorbit.js b/src/adapters/wideorbit.js index 8b051af934d..b725828fe78 100644 --- a/src/adapters/wideorbit.js +++ b/src/adapters/wideorbit.js @@ -4,7 +4,7 @@ var bidfactory = require('../bidfactory.js'), adloader = require('../adloader'); var WideOrbitAdapter = function WideOrbitAdapter() { - var pageImpression = 'JSAdservingMP.ashx?pc={pc}&pbId={pbId}&clk=&exm=&jsv=1.0&tsv=1.0&cts={cts}&arp=0&fl=0&vitp=&vit=&jscb=window.$$PREBID_GLOBAL$$.handleWideOrbitCallback&url=&fp=&oid=&exr=&mraid=&apid=&apbndl=&mpp=0&uid=&cb={cb}&hb=1', + var pageImpression = 'JSAdservingMP.ashx?pc={pc}&pbId={pbId}&clk=&exm=&jsv=1.0&tsv=1.0&cts={cts}&arp=0&fl=0&vitp=&vit=&jscb=window.$$PREBID_GLOBAL$$.handleWideOrbitCallback&url={referrer}&fp=&oid=&exr=&mraid=&apid=&apbndl=&mpp=0&uid=&cb={cb}&hb=1', pageRepeatCommonParam = '&gid{o}={gid}&pp{o}=&clk{o}=&rpos{o}={rpos}&ecpm{o}={ecpm}&ntv{o}=&ntl{o}=&adsid{o}=', pageRepeatParamId = '&pId{o}={pId}&rank{o}={rank}', pageRepeatParamNamed = '&wsName{o}={wsName}&wName{o}={wName}&rank{o}={rank}&bfDim{o}={width}x{height}&subp{o}={subp}', @@ -17,7 +17,7 @@ var WideOrbitAdapter = function WideOrbitAdapter() { return; } - var properties = ['site', 'page', 'width', 'height', 'rank', 'subPublisher', 'ecpm', 'atf', 'pId', 'pbId'], + var properties = ['site', 'page', 'width', 'height', 'rank', 'subPublisher', 'ecpm', 'atf', 'pId', 'pbId', 'referrer'], prop; utils._each(properties, function (correctName) { @@ -82,12 +82,13 @@ var WideOrbitAdapter = function WideOrbitAdapter() { ]); } - function _setupAdCall(publisherId, placementCount, placementsComponent) { + function _setupAdCall(publisherId, placementCount, placementsComponent, referrer) { return _setParams(base + pageImpression, [ ['pbId', publisherId], ['pc', placementCount], ['cts', new Date().getTime()], - ['cb', Math.floor(Math.random() * 100000000)] + ['cb', Math.floor(Math.random() * 100000000)], + ['referrer', encodeURIComponent(referrer || '')] ]) + placementsComponent; } @@ -104,7 +105,7 @@ var WideOrbitAdapter = function WideOrbitAdapter() { function _callBids(params) { var publisherId, bidUrl = '', - i; + i, referrer; bids = params.bids || []; @@ -116,10 +117,11 @@ var WideOrbitAdapter = function WideOrbitAdapter() { _fixParamNames(requestParams); publisherId = requestParams.pbId; + referrer = referrer || requestParams.referrer; bidUrl += _setupPlacementParameters(i, requestParams); } - bidUrl = _setupAdCall(publisherId, bids.length, bidUrl); + bidUrl = _setupAdCall(publisherId, bids.length, bidUrl, referrer); utils.logMessage('Calling WO: ' + bidUrl); diff --git a/src/adapters/xhb.js b/src/adapters/xhb.js index 722d97ebc91..be51e257cfd 100644 --- a/src/adapters/xhb.js +++ b/src/adapters/xhb.js @@ -8,6 +8,25 @@ const bidfactory = require('../bidfactory.js'); const XhbAdapter = function XhbAdapter() { + const _defaultBidderSettings = { + alwaysUseBid: true, + adserverTargeting: [ + { + key: 'hb_xhb_deal', + val: function (bidResponse) { + return bidResponse.dealId; + } + }, + { + key: 'hb_xhb_adid', + val: function (bidResponse) { + return bidResponse.adId; + } + } + ] + }; + bidmanager.registerDefaultBidderSetting('xhb', _defaultBidderSettings); + function buildJPTCall(bid, callbackId) { //determine tag params const placementId = utils.getBidIdParameter('placementId', bid.params); diff --git a/src/adserver.js b/src/adserver.js index 6760554dc69..b4ec8a22a63 100644 --- a/src/adserver.js +++ b/src/adserver.js @@ -30,9 +30,9 @@ exports.dfpAdserver = function (options, urlComponents) { adserver.appendQueryParams = function() { var bid = adserver.getWinningBidByCode(); - this.urlComponents.search.description_url = encodeURIComponent(bid.vastUrl); + this.urlComponents.search.description_url = encodeURIComponent(bid.descriptionUrl); this.urlComponents.search.cust_params = getCustomParams(bid.adserverTargeting); - this.urlComponents.correlator = Date.now(); + this.urlComponents.search.correlator = Date.now(); }; adserver.verifyAdserverTag = function() { diff --git a/src/bidmanager.js b/src/bidmanager.js index 380403b0d3d..69eed14c7c4 100644 --- a/src/bidmanager.js +++ b/src/bidmanager.js @@ -46,7 +46,7 @@ function bidsBackAdUnit(adUnitCode) { .map(request => request.bids .filter(adUnitsFilter.bind(this, $$PREBID_GLOBAL$$._adUnitCodes)) .filter(bid => bid.placementCode === adUnitCode)) - .reduce(flatten) + .reduce(flatten, []) .map(bid => { return bid.bidder === 'indexExchange' ? bid.sizes.length : @@ -64,7 +64,7 @@ function add(a, b) { function bidsBackAll() { const requested = $$PREBID_GLOBAL$$._bidsRequested .map(request => request.bids) - .reduce(flatten) + .reduce(flatten, []) .filter(adUnitsFilter.bind(this, $$PREBID_GLOBAL$$._adUnitCodes)) .map(bid => { return bid.bidder === 'indexExchange' ? @@ -93,6 +93,11 @@ function getBidderRequest(bidder, adUnitCode) { * This function should be called to by the bidder adapter to register a bid response */ exports.addBidResponse = function (adUnitCode, bid) { + if (!adUnitCode) { + utils.logWarn('No adUnitCode supplied to addBidResponse, response discarded'); + return; + } + if (bid) { const { requestId, start } = getBidderRequest(bid.bidderCode, adUnitCode); @@ -130,7 +135,7 @@ exports.addBidResponse = function (adUnitCode, bid) { //if there is any key value pairs to map do here var keyValues = {}; - if (bid.bidderCode && bid.cpm > 0) { + if (bid.bidderCode && (bid.cpm > 0 || bid.dealId ) ) { keyValues = getKeyValueTargetingPairs(bid.bidderCode, bid); } @@ -296,25 +301,15 @@ function processCallbacks(callbackQueue, singleAdUnitCode) { * groupByPlacement is a reduce function that converts an array of Bid objects * to an object with placement codes as keys, with each key representing an object * with an array of `Bid` objects for that placement - * @param prev previous value as accumulator object - * @param item current array item - * @param idx current index - * @param arr the array being reduced * @returns {*} as { [adUnitCode]: { bids: [Bid, Bid, Bid] } } */ -function groupByPlacement(prev, item, idx, arr) { - // this uses a standard "array to map" operation that could be abstracted further - if (item.adUnitCode in Object.keys(prev)) { - // if the adUnitCode key is present in the accumulator object, continue - return prev; - } else { - // otherwise add the adUnitCode key to the accumulator object and set to an object with an - // array of Bids for that adUnitCode - prev[item.adUnitCode] = { - bids: arr.filter(bid => bid.adUnitCode === item.adUnitCode) - }; - return prev; - } +function groupByPlacement(bidsByPlacement, bid) { + if (!bidsByPlacement[bid.adUnitCode]) + bidsByPlacement[bid.adUnitCode] = { bids: [] }; + + bidsByPlacement[bid.adUnitCode].bids.push(bid); + + return bidsByPlacement; } /** diff --git a/src/polyfill.js b/src/polyfill.js index 467a09f7cba..b6428e871a4 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -2,59 +2,15 @@ Misc polyfills */ /*jshint -W121 */ -if (!Array.prototype.find) { - Object.defineProperty(Array.prototype, "find", { - value: function(predicate) { - if (this === null) { - throw new TypeError('Array.prototype.find called on null or undefined'); - } - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - var list = Object(this); - var length = list.length >>> 0; - var thisArg = arguments[1]; - var value; +import shimArrayFind from 'array.prototype.find/shim'; +import shimArrayIncludes from 'array-includes/shim'; - for (var i = 0; i < length; i++) { - value = list[i]; - if (predicate.call(thisArg, value, i, list)) { - return value; - } - } - return undefined; - } - }); +if (!Array.prototype.find) { + shimArrayFind(); } if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, "includes", { - value: function(searchElement) { - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - } - }); + shimArrayIncludes(); } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger diff --git a/src/secure-creatives.js b/src/secure-creatives.js index e8f12ae860d..e559928bb79 100644 --- a/src/secure-creatives.js +++ b/src/secure-creatives.js @@ -43,6 +43,7 @@ function sendAdToCreative(adObject, remoteDomain, source) { message: 'Prebid Response', ad, adUrl, + adId, width, height }), remoteDomain); diff --git a/src/utils.js b/src/utils.js index 3fe2cf3127b..5cceb65d391 100644 --- a/src/utils.js +++ b/src/utils.js @@ -470,6 +470,19 @@ exports.createTrackPixelHtml = function (url) { return img; }; +/** + * Creates a snippet of Iframe HTML that retrieves the specified `url` + * @param {string} url plain URL to be requested + * @return {string} HTML snippet that contains the iframe src = set to `url` + */ +exports.createTrackPixelIframeHtml = function (url) { + if (!url) { + return ''; + } + + return ``; +}; + /** * Returns iframe document in a browser agnostic way * @param {object} iframe reference diff --git a/test/fixtures/allAdapters.js b/test/fixtures/allAdapters.js index 914f5def8f8..e2baa12cd10 100644 --- a/test/fixtures/allAdapters.js +++ b/test/fixtures/allAdapters.js @@ -1,3 +1,3 @@ exports.getAllAdaptersString = function () { - return `var AardvarkAdapter = require(\'./adapters/aardvark.js\');\n exports.registerBidAdapter(new AardvarkAdapter(), \'aardvark\');\nvar AdbladeAdapter = require(\'./adapters/adblade.js\');\n exports.registerBidAdapter(new AdbladeAdapter(), \'adblade\');\nvar AdbutlerAdapter = require(\'./adapters/adbutler.js\');\n exports.registerBidAdapter(new AdbutlerAdapter(), \'adbutler\');\nvar AdequantAdapter = require(\'./adapters/adequant.js\');\n exports.registerBidAdapter(new AdequantAdapter(), \'adequant\');\nvar AdformAdapter = require(\'./adapters/adform.js\');\n exports.registerBidAdapter(new AdformAdapter(), \'adform\');\nvar AdmediaAdapter = require(\'./adapters/admedia.js\');\n exports.registerBidAdapter(new AdmediaAdapter(), \'admedia\');\nvar AolAdapter = require(\'./adapters/aol.js\');\n exports.registerBidAdapter(new AolAdapter(), \'aol\');\nvar AppnexusAdapter = require(\'./adapters/appnexus.js\');\n exports.registerBidAdapter(new AppnexusAdapter(), \'appnexus\');\nvar AppnexusAstAdapter = require(\'./adapters/appnexusAst.js\');\n exports.registerBidAdapter(new AppnexusAstAdapter(), \'appnexusAst\');\nvar GetintentAdapter = require(\'./adapters/getintent.js\');\n exports.registerBidAdapter(new GetintentAdapter(), \'getintent\');\nvar HiromediaAdapter = require(\'./adapters/hiromedia.js\');\n exports.registerBidAdapter(new HiromediaAdapter(), \'hiromedia\');\nvar IndexExchangeAdapter = require(\'./adapters/indexExchange.js\');\n exports.registerBidAdapter(new IndexExchangeAdapter(), \'indexExchange\');\nvar KruxlinkAdapter = require(\'./adapters/kruxlink.js\');\n exports.registerBidAdapter(new KruxlinkAdapter(), \'kruxlink\');\nvar KomoonaAdapter = require(\'./adapters/komoona.js\');\n exports.registerBidAdapter(new KomoonaAdapter(), \'komoona\');\nvar OpenxAdapter = require(\'./adapters/openx.js\');\n exports.registerBidAdapter(new OpenxAdapter(), \'openx\');\nvar PiximediaAdapter = require(\'./adapters/piximedia.js\');\n exports.registerBidAdapter(new PiximediaAdapter(), \'piximedia\');\nvar PubmaticAdapter = require(\'./adapters/pubmatic.js\');\n exports.registerBidAdapter(new PubmaticAdapter(), \'pubmatic\');\nvar PulsepointAdapter = require(\'./adapters/pulsepoint.js\');\n exports.registerBidAdapter(new PulsepointAdapter(), \'pulsepoint\');\nvar RubiconAdapter = require(\'./adapters/rubicon.js\');\n exports.registerBidAdapter(new RubiconAdapter(), \'rubicon\');\nvar SonobiAdapter = require(\'./adapters/sonobi.js\');\n exports.registerBidAdapter(new SonobiAdapter(), \'sonobi\');\nvar SovrnAdapter = require(\'./adapters/sovrn.js\');\n exports.registerBidAdapter(new SovrnAdapter(), \'sovrn\');\nvar SpringserveAdapter = require(\'./adapters/springserve.js\');\n exports.registerBidAdapter(new SpringserveAdapter(), \'springserve\');\nvar TripleliftAdapter = require(\'./adapters/triplelift.js\');\n exports.registerBidAdapter(new TripleliftAdapter(), \'triplelift\');\nvar YieldbotAdapter = require(\'./adapters/yieldbot.js\');\n exports.registerBidAdapter(new YieldbotAdapter(), \'yieldbot\');\nvar NginadAdapter = require(\'./adapters/nginad.js\');\n exports.registerBidAdapter(new NginadAdapter(), \'nginad\');\nvar BrightcomAdapter = require(\'./adapters/brightcom.js\');\n exports.registerBidAdapter(new BrightcomAdapter(), \'brightcom\');\nvar WideorbitAdapter = require(\'./adapters/wideorbit.js\');\n exports.registerBidAdapter(new WideorbitAdapter(), \'wideorbit\');\nvar JcmAdapter = require(\'./adapters/jcm.js\');\n exports.registerBidAdapter(new JcmAdapter(), \'jcm\');\nvar UnderdogmediaAdapter = require(\'./adapters/underdogmedia.js\');\n exports.registerBidAdapter(new UnderdogmediaAdapter(), \'underdogmedia\');\nvar MemeglobalAdapter = require(\'./adapters/memeglobal.js\');\n exports.registerBidAdapter(new MemeglobalAdapter(), \'memeglobal\');\nvar CentroAdapter = require(\'./adapters/centro.js\');\n exports.registerBidAdapter(new CentroAdapter(), \'centro\');\nvar RoxotAdapter = require(\'./adapters/roxot.js\');\n exports.registerBidAdapter(new RoxotAdapter(), \'roxot\');\nexports.aliasBidAdapter(\'appnexus\',\'brealtime\');\nexports.aliasBidAdapter(\'appnexus\',\'pagescience\');\nexports.aliasBidAdapter(\'appnexus\',\'defymedia\');\nexports.videoAdapters = ["appnexusAst"];`; + return `var AardvarkAdapter = require(\'./adapters/aardvark.js\');\n exports.registerBidAdapter(new AardvarkAdapter(), \'aardvark\');\nvar AdbladeAdapter = require(\'./adapters/adblade.js\');\n exports.registerBidAdapter(new AdbladeAdapter(), \'adblade\');\nvar AdbutlerAdapter = require(\'./adapters/adbutler.js\');\n exports.registerBidAdapter(new AdbutlerAdapter(), \'adbutler\');\nvar AdequantAdapter = require(\'./adapters/adequant.js\');\n exports.registerBidAdapter(new AdequantAdapter(), \'adequant\');\nvar AdformAdapter = require(\'./adapters/adform.js\');\n exports.registerBidAdapter(new AdformAdapter(), \'adform\');\nvar AdmediaAdapter = require(\'./adapters/admedia.js\');\n exports.registerBidAdapter(new AdmediaAdapter(), \'admedia\');\nvar AolAdapter = require(\'./adapters/aol.js\');\n exports.registerBidAdapter(new AolAdapter(), \'aol\');\nvar AppnexusAdapter = require(\'./adapters/appnexus.js\');\n exports.registerBidAdapter(new AppnexusAdapter(), \'appnexus\');\nvar AppnexusAstAdapter = require(\'./adapters/appnexusAst.js\');\n exports.registerBidAdapter(new AppnexusAstAdapter(), \'appnexusAst\');\nvar GetintentAdapter = require(\'./adapters/getintent.js\');\n exports.registerBidAdapter(new GetintentAdapter(), \'getintent\');\nvar HiromediaAdapter = require(\'./adapters/hiromedia.js\');\n exports.registerBidAdapter(new HiromediaAdapter(), \'hiromedia\');\nvar IndexExchangeAdapter = require(\'./adapters/indexExchange.js\');\n exports.registerBidAdapter(new IndexExchangeAdapter(), \'indexExchange\');\nvar KruxlinkAdapter = require(\'./adapters/kruxlink.js\');\n exports.registerBidAdapter(new KruxlinkAdapter(), \'kruxlink\');\nvar KomoonaAdapter = require(\'./adapters/komoona.js\');\n exports.registerBidAdapter(new KomoonaAdapter(), \'komoona\');\nvar OpenxAdapter = require(\'./adapters/openx.js\');\n exports.registerBidAdapter(new OpenxAdapter(), \'openx\');\nvar PiximediaAdapter = require(\'./adapters/piximedia.js\');\n exports.registerBidAdapter(new PiximediaAdapter(), \'piximedia\');\nvar PubmaticAdapter = require(\'./adapters/pubmatic.js\');\n exports.registerBidAdapter(new PubmaticAdapter(), \'pubmatic\');\nvar PulsepointAdapter = require(\'./adapters/pulsepoint.js\');\n exports.registerBidAdapter(new PulsepointAdapter(), \'pulsepoint\');\nvar RubiconAdapter = require(\'./adapters/rubicon.js\');\n exports.registerBidAdapter(new RubiconAdapter(), \'rubicon\');\nvar SonobiAdapter = require(\'./adapters/sonobi.js\');\n exports.registerBidAdapter(new SonobiAdapter(), \'sonobi\');\nvar SovrnAdapter = require(\'./adapters/sovrn.js\');\n exports.registerBidAdapter(new SovrnAdapter(), \'sovrn\');\nvar SpringserveAdapter = require(\'./adapters/springserve.js\');\n exports.registerBidAdapter(new SpringserveAdapter(), \'springserve\');\nvar ThoughtleadrAdapter = require('./adapters/thoughtleadr.js');\n exports.registerBidAdapter(new ThoughtleadrAdapter(), 'thoughtleadr');\nvar TripleliftAdapter = require(\'./adapters/triplelift.js\');\n exports.registerBidAdapter(new TripleliftAdapter(), \'triplelift\');\nvar TwengaAdapter = require(\'./adapters/twenga.js\');\n exports.registerBidAdapter(new TwengaAdapter(), \'twenga\');\nvar YieldbotAdapter = require(\'./adapters/yieldbot.js\');\n exports.registerBidAdapter(new YieldbotAdapter(), \'yieldbot\');\nvar NginadAdapter = require(\'./adapters/nginad.js\');\n exports.registerBidAdapter(new NginadAdapter(), \'nginad\');\nvar BrightcomAdapter = require(\'./adapters/brightcom.js\');\n exports.registerBidAdapter(new BrightcomAdapter(), \'brightcom\');\nvar WideorbitAdapter = require(\'./adapters/wideorbit.js\');\n exports.registerBidAdapter(new WideorbitAdapter(), \'wideorbit\');\nvar JcmAdapter = require(\'./adapters/jcm.js\');\n exports.registerBidAdapter(new JcmAdapter(), \'jcm\');\nvar UnderdogmediaAdapter = require(\'./adapters/underdogmedia.js\');\n exports.registerBidAdapter(new UnderdogmediaAdapter(), \'underdogmedia\');\nvar MemeglobalAdapter = require(\'./adapters/memeglobal.js\');\n exports.registerBidAdapter(new MemeglobalAdapter(), \'memeglobal\');\nvar CentroAdapter = require(\'./adapters/centro.js\');\n exports.registerBidAdapter(new CentroAdapter(), \'centro\');\nvar RoxotAdapter = require(\'./adapters/roxot.js\');\n exports.registerBidAdapter(new RoxotAdapter(), \'roxot\');\nexports.aliasBidAdapter(\'appnexus\',\'brealtime\');\nexports.aliasBidAdapter(\'appnexus\',\'pagescience\');\nexports.aliasBidAdapter(\'appnexus\',\'defymedia\');\nexports.videoAdapters = ["appnexusAst"];`; }; diff --git a/test/spec/adapters/adbund_spec.js b/test/spec/adapters/adbund_spec.js new file mode 100644 index 00000000000..0714d041c83 --- /dev/null +++ b/test/spec/adapters/adbund_spec.js @@ -0,0 +1,96 @@ +import { expect } from 'chai'; +import Adapter from '../../../src/adapters/adbund'; +import bidManager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; + +describe('adbund adapter tests', function () { + + let sandbox; + let adapter; + let server; + + const request = { + bidderCode: 'adbund', + bids: [{ + bidder: 'adbund', + params: { + sid: '110238', + bidfloor: 0.036 + }, + placementCode: 'adbund', + sizes: [[300, 250]], + bidId: 'adbund_bidId', + bidderRequestId: 'adbund_bidderRequestId', + requestId: 'adbund_requestId' + }] + }; + + const response = { + bidderCode: 'adbund', + cpm: 1.06, + height: 250, + width: 300 + }; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('adbund callBids validation', () => { + + beforeEach(() => { + adapter = new Adapter(); + }); + + afterEach(() => { + }); + + it('Valid bid-request', () => { + let bidderRequest; + + sandbox.stub(adapter, 'callBids'); + adapter.callBids(request); + + bidderRequest = adapter.callBids.getCall(0).args[0]; + + expect(bidderRequest).to.have.property('bids') + .that.is.an('array') + .with.lengthOf(1); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('bidder', 'adbund'); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('sizes') + .that.is.an('array') + .with.lengthOf(1) + .that.deep.equals(request.bids[0].sizes); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('bidfloor', 0.036); + }); + + it('Valid bid-response', () => { + var bidderResponse; + + sandbox.stub(bidManager, 'addBidResponse'); + adapter.callBids(request); + bidderResponse = bidManager.addBidResponse.getCall(0) || + bidManager.addBidResponse.getCall(1); + + if (bidderResponse && bidderResponse.args && bidderResponse.args[1]) { + bidderResponse = bidderResponse.args[1]; + expect(bidderResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidderResponse.bidderCode).to.equal(response.bidderCode); + expect(bidderResponse.width).to.equal(response.width); + expect(bidderResponse.height).to.equal(response.height); + expect(bidderResponse.cpm).to.equal(response.cpm); + } + }); + }); +}); \ No newline at end of file diff --git a/test/spec/adapters/adform_spec.js b/test/spec/adapters/adform_spec.js index 74bd22bf59d..70ad3807259 100644 --- a/test/spec/adapters/adform_spec.js +++ b/test/spec/adapters/adform_spec.js @@ -81,6 +81,13 @@ describe('Adform adapter', () => { assert.equal(_bidObject.bidderCode, 'adform'); }); + it('should correctly set bid response adId', () => { + const addResponse = bidManager.addBidResponse; + assert.equal('abc', addResponse.getCall(0).args[1].adId); + assert.equal('123', addResponse.getCall(1).args[1].adId); + assert.equal('a1b', addResponse.getCall(2).args[1].adId); + }); + beforeEach(() => { sandbox.stub(bidManager, 'addBidResponse'); $$PREBID_GLOBAL$$._adf_callback([ @@ -112,6 +119,7 @@ describe('Adform adapter', () => { _adapter.callBids({ bids: [ { + bidId: 'abc', placementCode: 'code-1', sizes: [ [ 100, 100], [ 90, 90 ] ], params: { @@ -122,6 +130,7 @@ describe('Adform adapter', () => { tid: 45 }, { + bidId: '123', placementCode: 'code-2', sizes: [ [ 100, 100] ], params: { @@ -131,6 +140,7 @@ describe('Adform adapter', () => { } }, { + bidId: 'a1b', placementCode: 'code-3', sizes: [ [ 50, 40], [ 40, 50 ] ], params: { diff --git a/test/spec/adapters/adkernel_spec.js b/test/spec/adapters/adkernel_spec.js index 149f9c7a44d..4d692d32056 100644 --- a/test/spec/adapters/adkernel_spec.js +++ b/test/spec/adapters/adkernel_spec.js @@ -241,6 +241,17 @@ describe('Adkernel adapter', () => { expect(result.bids[0].ad).to.include(bidResponse1.seatbid[0].bid[0].nurl); }); + it('should perform usersync for each unique host/zone combination', () => { + ajaxStub.callsArgWith(1, ''); + const expectedSyncUrls = ['http://rtb.adkernel.com/user-sync?zone=1', 'http://rtb.adkernel.com/user-sync?zone=2', + 'http://rtb-private.adkernel.com/user-sync?zone=1']; + sandbox.spy(utils, 'createInvisibleIframe'); + doRequest([bid1_zone1, bid2_zone2, bid2_zone2, bid3_host2]); + expect(utils.createInvisibleIframe.calledThrice); + let userSyncUrls = utils.createInvisibleIframe.returnValues.map( val => val.src); + expect(userSyncUrls).to.be.eql(expectedSyncUrls); + }); + }); describe('adapter aliasing', () => { diff --git a/test/spec/adapters/appnexusAst_spec.js b/test/spec/adapters/appnexusAst_spec.js index c9b5afd07d9..273beac7629 100644 --- a/test/spec/adapters/appnexusAst_spec.js +++ b/test/spec/adapters/appnexusAst_spec.js @@ -122,7 +122,7 @@ describe('AppNexusAdapter', () => { adapter.callBids(REQUEST); - const request = JSON.parse(requests[0].requestBody).tags[0]; + const request = JSON.parse(requests[0].requestBody); expect(request.user).to.exist; expect(request.user).to.deep.equal({ external_uid: '123', diff --git a/test/spec/adapters/centro_spec.js b/test/spec/adapters/centro_spec.js index a3a8f184e92..abc83f6c603 100644 --- a/test/spec/adapters/centro_spec.js +++ b/test/spec/adapters/centro_spec.js @@ -78,7 +78,7 @@ describe('centro adapter tests', function () { var parsedBidUrl = urlParse(bidUrl1); var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - var generatedCallback = 'adCentroHandler_28136300x250'; + var generatedCallback = 'adCentroHandler_28136300x250div-gpt-ad-12345-1'; expect(parsedBidUrl.hostname).to.equal('staging.brand-server.com'); expect(parsedBidUrl.pathname).to.equal('/hb'); @@ -92,13 +92,13 @@ describe('centro adapter tests', function () { parsedBidUrl = urlParse(bidUrl2); parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - generatedCallback = 'adCentroHandler_28137728x90'; + generatedCallback = 'adCentroHandler_28137728x90div-gpt-ad-12345-2'; expect(parsedBidUrl.hostname).to.equal('t.brand-server.com'); expect(parsedBidUrl.pathname).to.equal('/hb'); expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('28137'); - expect(parsedBidUrlQueryString).to.not.have.property('url'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal(location.href); expect(parsedBidUrlQueryString).to.have.property('sz').and.to.equal('728x90'); expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal(generatedCallback); }); @@ -158,8 +158,10 @@ describe('centro adapter tests', function () { adapter().callBids(params); - expect(window['adCentroHandler_28136300x250']).to.exist.and.to.be.a('function'); - expect(window['adCentroHandler_111111728x90']).to.exist.and.to.be.a('function'); + expect(window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0']) + .to.exist.and.to.be.a('function'); + expect(window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1']) + .to.exist.and.to.be.a('function'); }); it('bidmanager.addBidResponse should be called with correct arguments', function () { @@ -189,10 +191,10 @@ describe('centro adapter tests', function () { var response3 = {"adTag":"","height":0,"value":0,"width":0,"sectionID":222222}; var response4 = ''; - window['adCentroHandler_28136300x250'](response); - window['adCentroHandler_111111728x90'](response2); - window['adCentroHandler_222222728x90'](response3); - window['adCentroHandler_333333728x90'](response4); + window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0'](response); + window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1'](response2); + window['adCentroHandler_222222728x90%2F19968336%2Fheader-bid-tag-2'](response3); + window['adCentroHandler_333333728x90%2F19968336%2Fheader-bid-tag-3'](response4); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; diff --git a/test/spec/adapters/getintent_spec.js b/test/spec/adapters/getintent_spec.js index 9560bf56c9c..64b33ba72ec 100644 --- a/test/spec/adapters/getintent_spec.js +++ b/test/spec/adapters/getintent_spec.js @@ -2,6 +2,8 @@ import Adapter from '../../../src/adapters/getintent'; import bidManager from '../../../src/bidmanager'; import {expect} from 'chai'; +var assert = require('chai').assert; + describe('getintent media adapter test', () => { let adapter; @@ -17,10 +19,16 @@ describe('getintent media adapter test', () => { cpm : 2.71, size : `${bidRequest.size}` }, bidRequest); - } else { + } else if (pid == "p3") { callback({ no_bid: 1 }, bidRequest); + } else if (pid == "p4") { + callback({ + vast_url : `http://test.com?pid=${pid}&tid=${tid}`, + cpm : 2.88, + size : `${bidRequest.size}` + }, bidRequest); } } }; @@ -58,6 +66,17 @@ describe('getintent media adapter test', () => { tid: "t2", cur: "USD" } + }, + { + bidder: "getintent", + adUnitCode: "test4", + mediaType: 'video', + sizes: [[480,352]], + params: { + pid: "p4", + tid: "t3", + cur: "USD" + } } ] }); @@ -75,6 +94,7 @@ describe('getintent media adapter test', () => { let firstBid; let secondBid; let thirdBid; + let videoBid; beforeEach(() => { sinon.stub(bidManager, 'addBidResponse'); @@ -82,14 +102,15 @@ describe('getintent media adapter test', () => { firstBid = bidManager.addBidResponse.firstCall.args[1]; secondBid = bidManager.addBidResponse.secondCall.args[1]; thirdBid = bidManager.addBidResponse.thirdCall.args[1]; + videoBid = bidManager.addBidResponse.lastCall.args[1]; }); afterEach(() => { bidManager.addBidResponse.restore(); }); - it('was called three times', () => { - sinon.assert.calledThrice(bidManager.addBidResponse); + it('was called four times', () => { + assert.strictEqual(bidManager.addBidResponse.callCount, 4); }); it('will respond to the first bid', () => { @@ -116,6 +137,13 @@ describe('getintent media adapter test', () => { expect(secondBid).to.have.property('bidderCode', 'getintent'); expect(thirdBid).to.have.property('bidderCode', 'getintent'); }); + + it('will respond to the video bid', () => { + expect(videoBid).to.have.property('vastUrl', 'http://test.com?pid=p4&tid=t3'); + expect(videoBid).to.have.property('cpm', 2.88); + expect(videoBid).to.have.property('width', '480'); + expect(videoBid).to.have.property('height', '352'); + }); }); }); diff --git a/test/spec/adapters/gumgum_spec.js b/test/spec/adapters/gumgum_spec.js index 58958373f94..9eb1a36ae08 100644 --- a/test/spec/adapters/gumgum_spec.js +++ b/test/spec/adapters/gumgum_spec.js @@ -2,6 +2,7 @@ import {expect} from 'chai'; import Adapter from '../../../src/adapters/gumgum'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; +import * as utils from '../../../src/utils'; import { STATUS } from '../../../src/constants'; describe('gumgum adapter', () => { @@ -73,10 +74,6 @@ describe('gumgum adapter', () => { }, "pag": pageParams }; - const emptyResponse = { - "ad": {}, - "pag": pageParams - } function mockBidResponse(response) { sandbox.stub(bidManager, 'addBidResponse'); @@ -102,11 +99,11 @@ describe('gumgum adapter', () => { adapter.callBids(bidderRequest); }); - it('should call the endpoint once per valid bid', () => { + it('calls the endpoint once per valid bid', () => { sinon.assert.callCount(adLoader.loadScript, 4); }); - it('should include required browser data', () => { + it('includes required browser data', () => { const endpointRequest = expect(adLoader.loadScript.firstCall.args[0]); endpointRequest.to.include('vw'); endpointRequest.to.include('vh'); @@ -114,12 +111,12 @@ describe('gumgum adapter', () => { endpointRequest.to.include('sh'); }); - it('should include the global bid timeout', () => { + it('includes the global bid timeout', () => { const endpointRequest = expect(adLoader.loadScript.firstCall.args[0]); endpointRequest.to.include(`tmax=${$$PREBID_GLOBAL$$.cbTimeout}`); }); - it('should include the publisher identity', () => { + it('includes the publisher identity', () => { const endpointRequest = expect(adLoader.loadScript.firstCall.args[0]); endpointRequest.to.include('t=' + TEST.PUBLISHER_IDENTITY); }); @@ -143,7 +140,7 @@ describe('gumgum adapter', () => { }); describe('handleGumGumCB[...]', () => { - it('should exist and be a function', () => { + it('exists and is function', () => { expect(pbjs.handleGumGumCB['InScreenBidId']).to.exist.and.to.be.a('function'); }); }); @@ -156,29 +153,29 @@ describe('gumgum adapter', () => { successfulBid = mockBidResponse(bidderResponse); }); - it('should add one bid', () => { + it('adds one bid', () => { sinon.assert.calledOnce(bidManager.addBidResponse); }); - it('should pass the correct placement code as the first param', () => { + it('passes the correct placement code as the first param', () => { const [ placementCode ] = bidManager.addBidResponse.firstCall.args; expect(placementCode).to.eql(TEST.PLACEMENT); }); - it('should have a GOOD status code', () => { + it('has a GOOD status code', () => { const STATUS_CODE = successfulBid.getStatusCode(); expect(STATUS_CODE).to.eql(STATUS.GOOD); }); - it('should use the CPM returned by the server', () => { + it('uses the CPM returned by the server', () => { expect(successfulBid).to.have.property('cpm', TEST.CPM); }); - it('should have an ad', () => { + it('has an ad', () => { expect(successfulBid).to.have.property('ad'); }); - it('should have the size specified by the server', () => { + it('has the size specified by the server', () => { expect(successfulBid).to.have.property('width', 728); expect(successfulBid).to.have.property('height', 90); }); @@ -190,26 +187,50 @@ describe('gumgum adapter', () => { let noBid; beforeEach(() => { - noBid = mockBidResponse(emptyResponse); + noBid = mockBidResponse(undefined); }); - it('should add one bid', () => { + it('adds one bid', () => { sinon.assert.calledOnce(bidManager.addBidResponse); }); - it('should have a NO_BID status code', () => { + it('has a NO_BID status code', () => { expect(noBid.getStatusCode()).to.eql(STATUS.NO_BID); }); - it('should pass the correct placement code as the first parameter', () => { + it('passes the correct placement code as the first parameter', () => { const [ placementCode ] = bidManager.addBidResponse.firstCall.args; expect(placementCode).to.eql(TEST.PLACEMENT); }); - it('should add the bidder code to the bid object', () => { + it('adds the bidder code to the bid object', () => { expect(noBid).to.have.property('bidderCode', TEST.BIDDER_CODE); }); }); + describe('refresh throttle', () => { + + beforeEach(() => { + mockBidResponse(bidderResponse); + }); + + afterEach(() => { + if (utils.logWarn.restore) { + utils.logWarn.restore(); + } + }); + + it('warns about the throttle limit', function() { + sinon.spy(utils, 'logWarn'); + // call all the binds again + adapter.callBids(bidderRequest); + // the timeout for in-screen should stop one bid request + const warning = expect(utils.logWarn.args[0][0]); + warning.to.include(TEST.PLACEMENT); + warning.to.include('inScreen'); + }); + + }); + }); diff --git a/test/spec/adapters/komoona_spec.js b/test/spec/adapters/komoona_spec.js index e99e4eae47b..f834004f80a 100644 --- a/test/spec/adapters/komoona_spec.js +++ b/test/spec/adapters/komoona_spec.js @@ -1,152 +1,158 @@ -describe("komoona adapter", function() { - var expect = require('chai').expect; - var adapter = require('src/adapters/komoona'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - var STATUS = require('src/constants').STATUS; - var startStub; - var bids = { - "bidderCode": "komoona", - "requestId": "1f43cc36a6a7e", - "bidderRequestId": "25392d757fad47", - "bids": [ - { - "bidder": "komoona", - "params": { - "hbid": "abcd", - "placementId": "efgh" - }, - "placementCode": "div-gpt-ad-1438287399331-0", - "sizes": [ - [300, 250] - ], - "bidId": "30e5e911c00703", - "bidderRequestId": "25392d757fad47", - "requestId": "1f43cc36a6a7e" - }, { - "bidder": "komoona", - "params": { - "hbid": "efgh", - "placementId": "ijkl" - }, - "placementCode": "div-gpt-ad-1438287399331-1", - "sizes": [ - [728, 90] - ], - "bidId": "48a0df61fac3ba", - "bidderRequestId": "25392d757fad47", - "requestId": "1f43cc36a6a7e" - } - ], - "start": 1466493146527 - }; - - beforeEach(function() { - // we don't want to really load the script. - sinon.stub(adLoader, 'loadScript', function(url, cb) { - cb(); - }); - //but let's create the global function it returns so we can stub it. - window.KmnKB = function() {}; - window.KmnKB.start = function() {}; - startStub = sinon.stub(window.KmnKB, 'start'); +import { expect } from 'chai'; +import Adapter from 'src/adapters/komoona'; +import bidmanager from 'src/bidmanager'; + +const ENDPOINT = '//bidder.komoona.com/v1/GetSBids'; + +const REQUEST = { + "bidderCode": "komoona", + "requestId": "1f43cc36a6a7e", + "bidderRequestId": "25392d757fad47", + "bids": [ + { + "bidder": "komoona", + "params": { + "hbid": "abcd666dcba", + "placementId": "abcd123123dcba" + }, + "placementCode": "div-gpt-ad-1438287399331-0", + "sizes": [ + [300, 250] + ], + "bidId": "30e5e911c00703", + "bidderRequestId": "25392d757fad47", + "requestId": "1f43cc36a6a7e" + } + ], + "start": 1466493146527 +}; + + +const RESPONSE = { + "bids": [ + { + "placementid": "abcd123123dcba", + "uuid": "30e5e911c00703", + "width": 728, + "height": 90, + "cpm": 0.5, + "creative": "" + } + ] +}; + +describe('komoonaAdapter', () => { + + let adapter; + + beforeEach(() => adapter = Adapter.createNew()); + + describe('request function', () => { + + let xhr; + let requests; + let pbConfig; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + pbConfig = REQUEST; + //just a single slot + pbConfig.bids = [pbConfig.bids[0]]; }); - afterEach(function() { - adLoader.loadScript.restore(); - window.KmnKB.start.restore(); + afterEach(() => xhr.restore()); + + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('requires paramters to make request', () => { + adapter.callBids({}); + expect(requests).to.be.empty; }); - it("sets kmncb config object correctly", function() { - adapter().callBids(bids); - - var startConfig = startStub.getCall(0).args[0]; - expect(startConfig).to.not.be.undefined; - expect(startConfig).to.have.property('hdbdid'); - expect(startConfig.hdbdid).to.equal('abcd'); - expect(startConfig).to.have.property('kb_callback'); - expect(startConfig.kb_callback).to.be.a.funtion; - expect(startConfig).to.have.property('ts_as'); - expect(startConfig).to.have.property('hb_placements'); - expect(startConfig.hb_placements).to.have.all.members(['efgh', 'ijkl']) - expect(startConfig).to.have.property('encode_bid'); - expect(startConfig.encode_bid).to.equal.undefined; - expect(startConfig).to.have.property('hb_placement_bidids'); - expect(startConfig.hb_placement_bidids).to.deep.equal({efgh: '30e5e911c00703', ijkl: '48a0df61fac3ba'}) + it('requires placementid and hbid', () => { + let backup = pbConfig.bids[0].params; + pbConfig.bids[0].params = {placementid : 1234}; //no hbid + adapter.callBids(pbConfig); + expect(requests).to.be.empty; + + pbConfig.bids[0].params = {hbid : 1234}; //no placementid + adapter.callBids(pbConfig); + expect(requests).to.be.empty; + + pbConfig.bids[0].params = backup; }); - it("registers arriving bids in bidManager", function() { - sinon.stub(bidmanager, 'addBidResponse'); - var bid_response = { - "cpm": 2.62, - "height": "250", - "width": "300", - "placementid": "efgh", - "creative": "blahblah", - "bidid": "30e5e911c00703" - }; - - pbjs._bidsRequested.push(bids); - adapter().callBids(bids); - - var startConfig = startStub.getCall(0).args[0]; - - //now let's call our callbak - startConfig.kb_callback(bid_response); - - var placementCode = bidmanager.addBidResponse.getCall(0).args[0]; - expect(placementCode).to.not.be.undefined; - expect(placementCode).to.equal('div-gpt-ad-1438287399331-0'); - var actualBidSent = bidmanager.addBidResponse.getCall(0).args[1]; - expect(actualBidSent).to.not.be.undefined; - expect(actualBidSent).to.have.property('getStatusCode'); - expect(actualBidSent.getStatusCode()).to.equal(STATUS.GOOD); - expect(actualBidSent).to.have.property('bidderCode', 'komoona'); - expect(actualBidSent).to.have.property('ad', 'blahblah'); - expect(actualBidSent).to.have.property('cpm', 2.62); - expect(actualBidSent).to.have.property('width', 300); - expect(actualBidSent).to.have.property('height', 250); - expect(actualBidSent).to.have.property('adId', '30e5e911c00703'); - bidmanager.addBidResponse.restore(); + it('sends bid request to ENDPOINT via POST', () => { + adapter.callBids(pbConfig); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('POST'); }); + }); + + describe('response handler', () => { - it("registers 'no-bid' bid if no ad is sent", function() { - sinon.stub(bidmanager, 'addBidResponse'); - var bid_response = { - "placementid": "efgh", - "bidid": "30e5e911c00703" - }; + let server; - pbjs._bidsRequested.push(bids); - adapter().callBids(bids); + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(bidmanager, 'addBidResponse'); + }); - var startConfig = startStub.getCall(0).args[0]; + afterEach(() => { + server.restore() + bidmanager.addBidResponse.restore(); + }); - //now let's call our callbak - startConfig.kb_callback(bid_response); + it('registers bids', () => { + server.respondWith(JSON.stringify(RESPONSE)); - var placementCode = bidmanager.addBidResponse.getCall(0).args[0]; - expect(placementCode).to.not.be.undefined; - expect(placementCode).to.equal('div-gpt-ad-1438287399331-0'); - var actualBidSent = bidmanager.addBidResponse.getCall(0).args[1]; - expect(actualBidSent).to.not.be.undefined; - expect(actualBidSent).to.have.property('getStatusCode'); - expect(actualBidSent.getStatusCode()).to.equal(STATUS.NO_BID); - expect(actualBidSent).to.have.property('bidderCode', 'komoona'); - expect(actualBidSent).to.have.property('adId', '30e5e911c00703'); - bidmanager.addBidResponse.restore(); - }) + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); - it("makes sure all is well with empty configuration", function() { - sinon.stub(bidmanager, 'addBidResponse'); + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('cpm', 0.5); + }); - var bid_response = {}; + it('handles nobid responses', () => { + server.respondWith(JSON.stringify({ + "bids": [{ + "cpm": 0, + "creative": "", + "uuid": "30e5e911c00703" + }] + })); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); - adapter().callBids(bid_response); + it('handles JSON.parse errors', () => { + server.respondWith(''); - //start should never be called - expect(startStub.getCall(0)).to.be.null; + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); - bidmanager.addBidResponse.restore(); + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); }); + + }); + }); diff --git a/test/spec/adapters/lifestreet_spec.js b/test/spec/adapters/lifestreet_spec.js new file mode 100644 index 00000000000..3ae2b6add2f --- /dev/null +++ b/test/spec/adapters/lifestreet_spec.js @@ -0,0 +1,231 @@ +import {expect} from 'chai'; +import adloader from 'src/adloader'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import LifestreetAdapter from 'src/adapters/lifestreet'; + +const BIDDER_REQUEST = { + auctionStart: new Date().getTime(), + bidderCode: 'lifestreet', + bidderRequestId: '42af176a304779', + bids: [{ + bidId: '5b19582c30a2d9', + bidder: 'lifestreet', + bidderRequestId: '42af176a304779', + params: { + ad_size: '160x600', + adkey: '78c', + jstag_url: '//ads.lfstmedia.com/getad?site=285071', + slot: 'slot166704', + timeout: 1500 + }, + placementCode: 'bar', + requestId: '6657bfa9-46b9-4ed8-9ce5-956f96efb13d', + sizes: [[160, 600]] + }], + requestId: '6657bfa9-46b9-4ed8-9ce5-956f96efb13d', + start: new Date().getTime() + 4, + timeout: 3000 +}; + +describe ('LifestreetAdapter', () => { + let adapter; + beforeEach(() => adapter = new LifestreetAdapter()); + + describe('callBids()', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + describe('request', () => { + let tagRequests; + let slotParams; + let request; + + beforeEach(() => { + tagRequests = []; + request = utils.extend(request, BIDDER_REQUEST); + sinon.stub(adloader, 'loadScript', (url, callback) => { + tagRequests.push(url); + callback(); + }); + slotParams = {}; + window.LSM_Slot = (params) => { + slotParams = params; + }; + }); + afterEach(() => { + adloader.loadScript.restore(); + window.LSM_Slot = undefined; + }); + + it('parameters should present', () => { + adapter.callBids({}); + expect(tagRequests).to.be.empty; + }); + + it('parameters do not have supported size', () => { + request.bids[0].sizes = [[728, 90], [970, 90]]; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it('tag when size is supported', () => { + request.bids[0].sizes = [[728, 90], [970, 90], [160, 600]]; + adapter.callBids(request); + expect(tagRequests.length).to.equal(1); + }); + + it('tag when one size is provided', () => { + request.bids[0].sizes = [160, 600]; + adapter.callBids(request); + expect(tagRequests.length).to.equal(1); + }); + + it('wrong size is provided', () => { + request.bids[0].sizes = [160]; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it('ad_size is not provided', () => { + request.bids[0].params.ad_size = ''; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it('slot is not provided', () => { + request.bids[0].params.slot = ''; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it ('adkey is not provided', () => { + request.bids[0].params.adkey = ''; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it('jstag_url is not provided', () => { + request.bids[0].params.jstag_url = ''; + adapter.callBids(request); + expect(tagRequests).to.be.empty; + }); + + it('should request a tag', () => { + window.LSM_Slot = undefined; + adapter.callBids(request); + expect(tagRequests.length).to.equal(1); + expect(tagRequests[0]).to.contain('ads.lfstmedia.com/getad?site=285071'); + }); + + it('LSM_Slot function should contain expected parameters', () => { + adapter.callBids(request); + expect(slotParams.ad_size).to.equal('160x600'); + expect(slotParams.adkey).to.equal('78c'); + expect(slotParams.slot).to.equal('slot166704'); + expect(slotParams._preload).to.equal('wait'); + expect(slotParams._hb_request).to.equal('prebidJS-1.0'); + expect(slotParams._timeout).to.equal(1500); + expect(slotParams).to.have.ownProperty('_onload'); + }); + + it('Default timeout should be 700 milliseconds', () => { + request.bids[0].params.timeout = 0; + adapter.callBids(request); + expect(slotParams._timeout).to.equal(700); + }); + }); + + describe('response', () => { + let slot; + let price; + let width; + let height; + + beforeEach(() => { + sinon.stub(bidmanager, 'addBidResponse'); + sinon.stub(adloader, 'loadScript', (url, callback) => { + callback(); + }); + slot = {}; + price = 1.0; + width = 160; + height = 600; + window.LSM_Slot = (params) => { + params._onload(slot, '', price, width, height); + }; + }); + afterEach(() => { + bidmanager.addBidResponse.restore(); + adloader.loadScript.restore(); + window.LSM_Slot = undefined; + }); + + it('nobid for undefined LSM_Slot function', () => { + window.LSM_Slot = undefined; + adapter.callBids(BIDDER_REQUEST); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); + }); + + it('nobid for error response', () => { + slot.state = () => { return 'error'; }; + adapter.callBids(BIDDER_REQUEST); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); + }); + + it('show existing slot', () => { + let isShown = false; + slot.state = () => { return 'loaded'; }; + slot.getSlotObjectName = () => { return ''; }; + slot.show = () => { isShown = true; }; + adapter.callBids(BIDDER_REQUEST); + expect(bidmanager.addBidResponse.calledOnce).to.be.false; + expect(isShown).to.be.true; + }); + + it('should bid', () => { + slot.state = () => { return 'loaded'; }; + slot.getSlotObjectName = () => { return 'Test Slot'; }; + adapter.callBids(BIDDER_REQUEST); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + let bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidResponse.getStatusCode()).to.equal(1); + expect(bidResponse.ad).to.equal(`
+ + `); + expect(bidResponse.cpm).to.equal(1.0); + expect(bidResponse.width).to.equal(160); + expect(bidResponse.height).to.equal(600); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/spec/adapters/mantis_spec.js b/test/spec/adapters/mantis_spec.js new file mode 100644 index 00000000000..094baad8239 --- /dev/null +++ b/test/spec/adapters/mantis_spec.js @@ -0,0 +1,166 @@ +'use strict'; + +describe('mantis adapter tests', function () { + const expect = require('chai').expect; + const adapter = require('src/adapters/mantis.js'); + const bidmanager = require('src/bidmanager'); + const adloader = require('src/adloader'); + const constants = require('src/constants.json'); + + var mantis, sandbox; + + beforeEach(() => { + mantis = new adapter(); + sandbox = sinon.sandbox.create(); + }); + + + afterEach(() => { + sandbox.restore(); + + delete window.context; + delete window.mantis_link; + delete window.mantis_breakpoint; + delete window.mantis_uuid; + }); + + var callBidExample = { + bidderCode: 'mantis', + bids: [ + { + bidId: 'bidId1', + bidder: 'mantis', + placementCode: 'foo', + sizes: [[728, 90]], + params: { + property: '1234' + } + }, + { + bidId: 'bidId2', + bidder: 'mantis', + placementCode: 'bar', + sizes: [[300, 600], [300, 250]], + params: { + property: '1234' + } + } + ] + }; + + describe('callBids', () => { + it('should create appropriate bid responses', () => { + sandbox.stub(bidmanager, 'addBidResponse'); + sandbox.stub(adloader, 'loadScript', function (url) { + var jsonp = eval(decodeURIComponent(url.match(/jsonp=(.*)&property/)[1])); + + jsonp({ + ads: { + bidId1: { + cpm: 1, + html: '', + width: 300, + height: 600 + } + } + }); + }); + + mantis.callBids(callBidExample); + + sinon.assert.calledTwice(bidmanager.addBidResponse); + + expect(bidmanager.addBidResponse.firstCall.args[0]).to.eql('foo'); + + var bid1 = bidmanager.addBidResponse.firstCall.args[1]; + expect(bid1.getStatusCode()).to.eql(constants.STATUS.GOOD); + expect(bid1.bidderCode).to.eql('mantis'); + expect(bid1.cpm).to.eql(1); + expect(bid1.ad).to.eql(''); + expect(bid1.width).to.eql(300); + expect(bid1.height).to.eql(600); + + expect(bidmanager.addBidResponse.secondCall.args[0]).to.eql('bar'); + + var bid2 = bidmanager.addBidResponse.secondCall.args[1]; + expect(bid2.getStatusCode()).to.eql(constants.STATUS.NO_BID); + expect(bid2.bidderCode).to.eql('mantis'); + }); + + it('should load script with relevant bid data', () => { + sandbox.stub(adloader, 'loadScript'); + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.match(/buster=[0-9]+&/); + expect(serverCall).to.match(/tz=[0-9]+&/); + expect(serverCall).to.match(/secure=(true|false)&/); + expect(serverCall).to.string('property=1234&'); + expect(serverCall).to.string('bids[0][bidId]=bidId1&'); + expect(serverCall).to.string('bids[0][sizes][0][width]=728&'); + expect(serverCall).to.string('bids[0][sizes][0][height]=90&'); + expect(serverCall).to.string('bids[1][bidId]=bidId2&'); + expect(serverCall).to.string('bids[1][sizes][0][width]=300&'); + expect(serverCall).to.string('bids[1][sizes][0][height]=600&'); + expect(serverCall).to.string('bids[1][sizes][1][width]=300&'); + expect(serverCall).to.string('bids[1][sizes][1][height]=250&'); + expect(serverCall).to.string('version=1'); + }); + + /* tests below are to just adhere to code coverage requirements, but it is already tested in our own libraries/deployment process */ + it('should send uuid from window if set', () => { + sandbox.stub(adloader, 'loadScript'); + + window.mantis_uuid = '4321'; + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('uuid=4321&'); + }); + + it('should send mobile = true if breakpoint is hit', () => { + sandbox.stub(adloader, 'loadScript'); + + window.mantis_link = true; // causes iframe detection to not work + window.mantis_breakpoint = 100000000; // force everything to be mobile + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('mobile=true&'); + }); + + it('should send different params if amp is detected', () => { + sandbox.stub(adloader, 'loadScript'); + + window.context = { + tagName: "AMP-AD", + location: { + href: 'bar', + referrer: 'baz' + } + }; + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('mobile=true&'); + expect(serverCall).to.string('url=bar&'); + }); + }); +}); + diff --git a/test/spec/adapters/memeglobal_spec.js b/test/spec/adapters/memeglobal_spec.js index 7221cb92984..278d7986000 100644 --- a/test/spec/adapters/memeglobal_spec.js +++ b/test/spec/adapters/memeglobal_spec.js @@ -161,7 +161,7 @@ describe('memeglobal adapter tests', function () { expect(bidObject1.cpm).to.equal(0.09); expect(bidObject1.height).to.equal(250); expect(bidObject1.width).to.equal(300); - expect(bidObject1.ad).to.equal('ad-code'); + expect(bidObject1.ad).to.equal('ad-code'); stubAddBidResponse.calledThrice; diff --git a/test/spec/adapters/openx_spec.js b/test/spec/adapters/openx_spec.js index f66b9029aa3..50d71064da7 100644 --- a/test/spec/adapters/openx_spec.js +++ b/test/spec/adapters/openx_spec.js @@ -7,6 +7,9 @@ describe('openx adapter tests', function () { const adloader = require('src/adloader'); const CONSTANTS = require('src/constants.json'); + before(() => sinon.stub(document.body, 'appendChild')); + after(() => document.body.appendChild.restore()); + describe('test openx callback responce', function () { it('should exist and be a function', function () { @@ -135,6 +138,77 @@ describe('openx adapter tests', function () { stubAddBidResponse.restore(); }); + it('should add no fill bid responses if bids are returned, but have empty pub rev', function () { + let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + let bidderRequest = { + bidderCode: 'openx', + bids: [ + { + bidId: 'bidId1', + bidder: 'openx', + params: { + delDomain: 'delDomain1', + unit: '1234' + }, + sizes: [[300, 250]], + placementCode: 'test-gpt-div-1234' + } + ] + }; + + // Empty pub rev in bid response + let response = { + "ads": + { + "version": 1, + "count": 1, + "pixels": "http://testpixels.net", + "ad": [ + { + "adunitid": 1234, + "adid": 5678, + "type": "html", + "html": "test_html", + "framed": 1, + "is_fallback": 1, + "ts": "ts", + "cpipc": 1000, + "pub_rev": "", + "adv_id": "adv_id", + "brand_id": "", + "creative": [ + { + "width": "300", + "height": "250", + "target": "_blank", + "mime": "text/html", + "media": "test_media", + "tracking": { + "impression": "test_impression", + "inview": "test_inview", + "click": "test_click" + } + } + ] + }] + } + }; + + pbjs._bidsRequested.push(bidderRequest); + // adapter needs to be called, in order for the stub to register. + adapter(); + + pbjs.oxARJResponse(response); + + let bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + let bidResponse1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidPlacementCode1).to.equal('test-gpt-div-1234'); + expect(bidResponse1.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(bidResponse1.bidderCode).to.equal('openx'); + stubAddBidResponse.restore(); + }); + it('should not call loadscript when inputting with empty params', function () { let spyLoadScript = sinon.spy(adloader, 'loadScript'); adapter().callBids({}); diff --git a/test/spec/adapters/rubicon_spec.js b/test/spec/adapters/rubicon_spec.js index ff3a7050249..cc16579c29d 100644 --- a/test/spec/adapters/rubicon_spec.js +++ b/test/spec/adapters/rubicon_spec.js @@ -7,18 +7,38 @@ import {parse as parseQuery} from 'querystring'; var CONSTANTS = require('src/constants.json'); +const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid + describe('the rubicon adapter', () => { let sandbox, adUnit, bidderRequest; + function createVideoBidderRequest() { + let bid = bidderRequest.bids[0]; + bid.mediaType = 'video'; + bid.params.video = { + 'language': 'en', + 'p_aso.video.ext.skip': true, + 'p_aso.video.ext.skipdelay': 15, + 'playerHeight': 320, + 'playerWidth': 640, + 'size_id': 201, + 'aeParams': { + 'p_aso.video.ext.skip': '1', + 'p_aso.video.ext.skipdelay': '15' + } + }; + } + beforeEach(() => { sandbox = sinon.sandbox.create(); adUnit = { code: '/19968336/header-bid-tag-0', sizes: [[300, 250], [320, 50]], + mediaType: 'video', bids: [ { bidder: 'rubicon', @@ -75,6 +95,7 @@ describe('the rubicon adapter', () => { } ], start: 1472239426002, + auctionStart: 1472239426000, timeout: 5000 }; @@ -93,7 +114,7 @@ describe('the rubicon adapter', () => { sandbox.stub(rubiconAdapter, 'callBids'); adapterManager.callBids({ - adUnits: [clone(adUnit)] + adUnits: [clone(adUnit)] }); let bidderRequest = rubiconAdapter.callBids.getCall(0).args[0]; @@ -105,6 +126,9 @@ describe('the rubicon adapter', () => { expect(bidderRequest).to.have.deep.property('bids[0]') .to.have.property('bidder', 'rubicon'); + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('mediaType', 'video'); + expect(bidderRequest).to.have.deep.property('bids[0]') .to.have.property('placementCode', adUnit.code); @@ -148,7 +172,7 @@ describe('the rubicon adapter', () => { ordering = masSizeOrdering([[120, 600], [320, 50], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); expect(ordering).to.deep.equal([2, 9, 8, 16, 43, 65, 126]); - }) + }); }); @@ -156,7 +180,7 @@ describe('the rubicon adapter', () => { let rubiconAdapter; - describe('requests', () => { + describe('for requests', () => { let xhr, bids; @@ -177,84 +201,173 @@ describe('the rubicon adapter', () => { xhr.restore(); }); - it('should make a well-formed optimized request', () => { - - rubiconAdapter.callBids(bidderRequest); - - let request = xhr.requests[0]; - - let [path, query] = request.url.split('?'); - query = parseQuery(query); - - expect(path).to.equal( - '//fastlane.rubiconproject.com/a/api/fastlane.json' - ); - - let expectedQuery = { - 'account_id': '14062', - 'site_id': '70608', - 'zone_id': '335918', - 'size_id': '15', - 'alt_size_ids': '43', - 'p_pos': 'atf', - 'rp_floor': '0.01', - 'tk_flint': 'pbjs.lite', - 'p_screen_res': /\d+x\d+/, - 'tk_user_key': '12346', - 'kw': 'a,b,c', - 'tg_v.ucat': 'new', - 'tg_v.lastsearch': 'iphone', - 'tg_i.rating': '5-star', - 'tg_i.prodtype': 'tech', - 'rf': 'localhost' - }; - - // test that all values above are both present and correct - Object.keys(expectedQuery).forEach(key => { - let value = expectedQuery[key]; - if(value instanceof RegExp) { - expect(query[key]).to.match(value); - } else { - expect(query[key]).to.equal(value); - } + describe("to fastlane", () => { + + it('should make a well-formed request', () => { + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let [path, query] = request.url.split('?'); + query = parseQuery(query); + + expect(path).to.equal( + '//fastlane.rubiconproject.com/a/api/fastlane.json' + ); + + let expectedQuery = { + 'account_id': '14062', + 'site_id': '70608', + 'zone_id': '335918', + 'size_id': '15', + 'alt_size_ids': '43', + 'p_pos': 'atf', + 'rp_floor': '0.01', + 'tk_flint': INTEGRATION, + 'p_screen_res': /\d+x\d+/, + 'tk_user_key': '12346', + 'kw': 'a,b,c', + 'tg_v.ucat': 'new', + 'tg_v.lastsearch': 'iphone', + 'tg_i.rating': '5-star', + 'tg_i.prodtype': 'tech', + 'rf': 'localhost' + }; + + // test that all values above are both present and correct + Object.keys(expectedQuery).forEach(key => { + let value = expectedQuery[key]; + if(value instanceof RegExp) { + expect(query[key]).to.match(value); + } else { + expect(query[key]).to.equal(value); + } + }); + + expect(query).to.have.property('rand'); + }); - expect(query).to.have.property('rand'); + it('should use rubicon sizes if present', () => { - }); + var sizesBidderRequest = clone(bidderRequest); + sizesBidderRequest.bids[0].params.sizes = [55, 57, 59]; + + rubiconAdapter.callBids(sizesBidderRequest); + + let query = parseQuery(xhr.requests[0].url.split('?')[1]); - it('should use rubicon sizes if present', () => { + expect(query['size_id']).to.equal('55'); + expect(query['alt_size_ids']).to.equal('57,59'); + + }); + + it('should not send a request and register an error bid if no valid sizes', () => { - var sizesBidderRequest = clone(bidderRequest); - sizesBidderRequest.bids[0].params.sizes = [55, 57, 59]; + var sizesBidderRequest = clone(bidderRequest); + sizesBidderRequest.bids[0].sizes = [[620,250],[300,251]]; - rubiconAdapter.callBids(sizesBidderRequest); + rubiconAdapter.callBids(sizesBidderRequest); + + expect(xhr.requests.length).to.equal(0); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + + }); + + it('should allow a floor override', () => { - let query = parseQuery(xhr.requests[0].url.split('?')[1]); + var floorBidderRequest = clone(bidderRequest); + floorBidderRequest.bids[0].params.floor = 2; - expect(query['size_id']).to.equal('55'); - expect(query['alt_size_ids']).to.equal('57,59'); + rubiconAdapter.callBids(floorBidderRequest); + + let query = parseQuery(xhr.requests[0].url.split('?')[1]); + + expect(query['rp_floor']).to.equal('2'); + + }); }); - it('should not send a request and register an error bid if no valid sizes', () => { + describe('for video requests', () => { + + beforeEach(() => { + createVideoBidderRequest(); + + sandbox.stub(Date, "now", () => + bidderRequest.auctionStart + 100 + ); + }); + + it('should make a well-formed video request', () => { + + rubiconAdapter.callBids(bidderRequest); - var sizesBidderRequest = clone(bidderRequest); - sizesBidderRequest.bids[0].sizes = [[620,250],[300,251]]; + let request = xhr.requests[0]; - rubiconAdapter.callBids(sizesBidderRequest); + let url = request.url; + let post = JSON.parse(request.requestBody); - expect(xhr.requests.length).to.equal(0); + expect(url).to.equal('//optimized-by-adv.rubiconproject.com/v1/auction/video'); - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(post).to.have.property('page_url').that.is.a('string'); + expect(post.resolution).to.match(/\d+x\d+/); + expect(post.account_id).to.equal('14062'); + expect(post.integration).to.equal(INTEGRATION); + expect(post).to.have.property('timeout').that.is.a('number'); + expect(post.timeout < 5000).to.equal(true); + expect(post.stash_creatives).to.equal(true); + + expect(post).to.have.property('ae_pass_through_parameters'); + expect(post.ae_pass_through_parameters) + .to.have.property('p_aso.video.ext.skip') + .that.equals('1'); + expect(post.ae_pass_through_parameters) + .to.have.property('p_aso.video.ext.skipdelay') + .that.equals('15'); + + expect(post).to.have.property('slots') + .with.length.of(1); + + let slot = post.slots[0]; + + expect(slot.site_id).to.equal('70608'); + expect(slot.zone_id).to.equal('335918'); + expect(slot.position).to.equal('atf'); + expect(slot.floor).to.equal(.01); + expect(slot.element_id).to.equal(bidderRequest.bids[0].placementCode); + expect(slot.name).to.equal(bidderRequest.bids[0].placementCode); + expect(slot.language).to.equal('en'); + expect(slot.width).to.equal(640); + expect(slot.height).to.equal(320); + expect(slot.size_id).to.equal(201); + + expect(slot).to.have.property('inventory').that.is.an('object'); + expect(slot.inventory).to.have.property('rating').that.equals('5-star'); + expect(slot.inventory).to.have.property('prodtype').that.equals('tech'); + + expect(slot).to.have.property('keywords') + .that.is.an('array') + .of.length(3) + .that.deep.equals(['a', 'b', 'c']); + + expect(slot).to.have.property('visitor').that.is.an('object'); + expect(slot.visitor).to.have.property('ucat').that.equals('new'); + expect(slot.visitor).to.have.property('lastsearch').that.equals('iphone'); + + }); }); }); + + describe('response handler', () => { let bids, server, @@ -278,217 +391,278 @@ describe('the rubicon adapter', () => { server.restore(); }); - it('should handle a success response and sort by cpm', () => { - - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [ - { - "status": "ok", - "impression_id": "153dc240-8229-4604-b8f5-256933b9374c", - "size_id": "15", - "ad_id": "6", - "advertiser": 7, - "network": 8, - "creative_id": 9, - "type": "script", - "script": "alert('foo')", - "campaign_id": 10, - "cpm": 0.811, - "targeting": [ + describe('for fastlane', () => { + + it('should handle a success response and sort by cpm', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [ + { + "status": "ok", + "impression_id": "153dc240-8229-4604-b8f5-256933b9374c", + "size_id": "15", + "ad_id": "6", + "advertiser": 7, + "network": 8, + "creative_id": 9, + "type": "script", + "script": "alert('foo')", + "campaign_id": 10, + "cpm": 0.811, + "targeting": [ + { + "key": "rpfl_14062", + "values": [ + "15_tier_all_test" + ] + } + ] + }, + { + "status": "ok", + "impression_id": "153dc240-8229-4604-b8f5-256933b9374d", + "size_id": "43", + "ad_id": "7", + "advertiser": 7, + "network": 8, + "creative_id": 9, + "type": "script", + "script": "alert('foo')", + "campaign_id": 10, + "cpm": 0.911, + "targeting": [ + { + "key": "rpfl_14062", + "values": [ + "15_tier_all_test" + ] + } + ] + } + ] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledTwice).to.equal(true); + + expect(bids).to.be.lengthOf(2); + + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal("rubicon"); + expect(bids[0].width).to.equal(320); + expect(bids[0].height).to.equal(50); + expect(bids[0].cpm).to.equal(0.911); + expect(bids[0].ad).to.contain(`alert('foo')`) + .and.to.contain(``) + .and.to.contain(`
`); + + expect(bids[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[1].bidderCode).to.equal("rubicon"); + expect(bids[1].width).to.equal(300); + expect(bids[1].height).to.equal(250); + expect(bids[1].cpm).to.equal(0.811); + expect(bids[1].ad).to.contain(`alert('foo')`) + .and.to.contain(``) + .and.to.contain(`
`); + }); + + it('should be fine with a CPM of 0', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "ok", + "cpm": 0, + "size_id": 15 + }] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + }); + + it('should handle an error with no ads returned', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should handle an error with bad status', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "not_ok", + }] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should handle an error because of malformed json response', () => { + server.respondWith("{test{"); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should not register an error bid when a success call to addBidResponse throws an error', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "ok", + "cpm": .8, + "size_id": 15 + }] + })); + + addBidResponseAction = function() { + throw new Error("test error"); + }; + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + // was calling twice for same bid, but should only call once + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + + }); + + }); + + describe('for video', () => { + + beforeEach(() => { + createVideoBidderRequest(); + }); + + it('should register a successful bid', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "ads": { + "/19968336/header-bid-tag-0": [ { - "key": "rpfl_14062", - "values": [ - "15_tier_all_test" - ] + "status": "ok", + "cpm": 1, + "tier": "tier0200", + "targeting": { + "rpfl_8000": "201_tier0200", + "rpfl_elemid": "/19968336/header-bid-tag-0" + }, + "impression_id": "a40fe16e-d08d-46a9-869d-2e1573599e0c", + "site_id": 88888, + "zone_id": 54321, + "creative_type": "video", + "creative_depot_url": "https://optimized-by-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml", + "ad_id": 999999, + "size_id": 201, + "advertiser": 12345 } ] }, - { - "status": "ok", - "impression_id": "153dc240-8229-4604-b8f5-256933b9374d", - "size_id": "43", - "ad_id": "7", - "advertiser": 7, - "network": 8, - "creative_id": 9, - "type": "script", - "script": "alert('foo')", - "campaign_id": 10, - "cpm": 0.911, - "targeting": [ - { - "key": "rpfl_14062", - "values": [ - "15_tier_all_test" - ] - } - ] - } - ] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledTwice).to.equal(true); - - expect(bids).to.be.lengthOf(2); - - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[0].bidderCode).to.equal("rubicon"); - expect(bids[0].width).to.equal(320); - expect(bids[0].height).to.equal(50); - expect(bids[0].cpm).to.equal(0.911); - expect(bids[0].ad).to.contain(`alert('foo')`) - .and.to.contain(``) - .and.to.contain(`
`); - - expect(bids[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[1].bidderCode).to.equal("rubicon"); - expect(bids[1].width).to.equal(300); - expect(bids[1].height).to.equal(250); - expect(bids[1].cpm).to.equal(0.811); - expect(bids[1].ad).to.contain(`alert('foo')`) - .and.to.contain(``) - .and.to.contain(`
`); - }); + "account_id": 7780 + })); - it('should be fine with a CPM of 0', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "ok", - "cpm": 0, - "size_id": 15 - }] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - }); + rubiconAdapter.callBids(bidderRequest); - it('should handle an error with no ads returned', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); - - it('should handle an error with bad status', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "not_ok", - }] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); + server.respond(); - it('should handle an error because of malformed json response', () => { - server.respondWith("{test{"); + // was calling twice for same bid, but should only call once + expect(bidManager.addBidResponse.calledOnce).to.equal(true); - rubiconAdapter.callBids(bidderRequest); + expect(bids).to.be.lengthOf(1); - server.respond(); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal('rubicon'); + expect(bids[0].creative_id).to.equal(999999); + expect(bids[0].cpm).to.equal(1); + expect(bids[0].descriptionUrl).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); + expect(bids[0].vastUrl).to.equal( + 'https://optimized-by-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml' + ); + expect(bids[0].impression_id).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); - - it('should not register an error bid when a success call to addBidResponse throws an error', () => { - - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "ok", - "cpm": .8, - "size_id": 15 - }] - })); - - addBidResponseAction = function() { - throw new Error("test error"); - }; - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - // was calling twice for same bid, but should only call once - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); + }); }); - }) + }); }); @@ -497,4 +671,4 @@ describe('the rubicon adapter', () => { function clone(obj) { return JSON.parse(JSON.stringify(obj)); -} \ No newline at end of file +} diff --git a/test/spec/adapters/smartadserver_spec.js b/test/spec/adapters/smartadserver_spec.js index d5989d679b1..f48f10d9cb5 100644 --- a/test/spec/adapters/smartadserver_spec.js +++ b/test/spec/adapters/smartadserver_spec.js @@ -18,7 +18,8 @@ describe("smartadserver adapter tests", function () { siteId: "1234", pageId: "5678", formatId: "90", - target: "test=prebid" + target: "test=prebid", + currency: "EUR" }, requestId: "efgh5678", placementCode: "sas_42" @@ -26,6 +27,24 @@ describe("smartadserver adapter tests", function () { ] }; + var DEFAULT_PARAMS_WO_OPTIONAL = { + bidderCode: "smartadserver", + bids: [{ + bidId: "abcd1234", + sizes: [[300, 250], [300, 200]], + bidder: "smartadserver", + params: { + domain: "http://www.smartadserver.com", + siteId: "1234", + pageId: "5678", + formatId: "90" + }, + requestId: "efgh5678", + placementCode: "sas_42" + } + ] + }; + var BID_RESPONSE = { cpm: 0.42, ad: "fake ad content", @@ -58,6 +77,7 @@ describe("smartadserver adapter tests", function () { expect(parsedBidUrlQueryString).to.have.property("pgid").and.to.equal("5678"); expect(parsedBidUrlQueryString).to.have.property("fmtid").and.to.equal("90"); expect(parsedBidUrlQueryString).to.have.property("tgt").and.to.equal("test=prebid"); + expect(parsedBidUrlQueryString).to.have.property("ccy").and.to.equal("EUR"); expect(parsedBidUrlQueryString).to.have.property("tag").and.to.equal("sas_42"); expect(parsedBidUrlQueryString).to.have.property("sizes").and.to.equal("300x250,300x200"); expect(parsedBidUrlQueryString).to.have.property("async").and.to.equal("1"); @@ -65,6 +85,21 @@ describe("smartadserver adapter tests", function () { stubLoadScript.restore(); }); + it("test optional parameters default value", function () { + var stubLoadScript = sinon.stub(adLoader, "loadScript"); + + adapter().callBids(DEFAULT_PARAMS_WO_OPTIONAL); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrlQueryString).to.have.property("tgt").and.to.equal(""); + expect(parsedBidUrlQueryString).to.have.property("ccy").and.to.equal("USD"); + + stubLoadScript.restore(); + }); + it("creates an empty bid response if no bids", function() { var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { var bidUrl = stubLoadScript.getCall(0).args[0]; diff --git a/test/spec/adapters/stickyadstv_spec.js b/test/spec/adapters/stickyadstv_spec.js new file mode 100644 index 00000000000..eb665ec658c --- /dev/null +++ b/test/spec/adapters/stickyadstv_spec.js @@ -0,0 +1,222 @@ +import {expect} from 'chai'; +import {assert} from 'chai'; +import Adapter from '../../../src/adapters/stickyadstv'; +import bidManager from '../../../src/bidmanager'; +import adLoader from '../../../src/adloader'; + +describe('StickyAdsTV Adapter', function () { + var adapter = void 0; + var sandbox = void 0; + var bidsRequestBuff = void 0; + var bidderRequest = { + bidderCode: 'stickyadstv', + bids: [{ + bidId: 'bidId1', + bidder: 'stickyadstv', + placementCode: 'foo', + sizes: [[300, 250]], + params: { + zoneId: '2003', + format:"screen-roll" + } + }, { + bidId: 'bidId2', + bidder: 'stickyadstv', + placementCode: 'bar', + sizes: [[728, 90]], + params: { + zoneId: '5562003' + } + }, { + bidId: 'bidId3', + bidder: 'stickyadstv', + placementCode: '', + sizes: [[300, 600]], + params: { + zoneId: '123456' + } + }, { + bidId: 'bidId4', + bidder: 'stickyadstv', + placementCode: 'coo', + sizes: [[300, 600]], + params: { + wrong: "missing zoneId" + } + }] + }; + + beforeEach(function () { + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + bidsRequestBuff = pbjs._bidsRequested; + pbjs._bidsRequested = []; + }); + + afterEach(function () { + sandbox.restore(); + pbjs._bidsRequested = bidsRequestBuff; + }); + + describe('callBids', function () { + beforeEach(function () { + sandbox.stub(adLoader, 'loadScript'); + adapter.callBids(bidderRequest); + }); + + it('should be called twice', function () { + sinon.assert.calledTwice(adLoader.loadScript); + }); + + it('should have load screenroll and mustang script', function () { + var url = void 0; + + url = adLoader.loadScript.firstCall.args[0]; + expect(url).to.equal("//cdn.stickyadstv.com/prime-time/screen-roll.min.js"); + + url = adLoader.loadScript.secondCall.args[0]; + expect(url).to.equal("//cdn.stickyadstv.com/mustang/mustang.min.js"); + }); + }); + + describe('getBid', function () { + let bidResponse; + let loadConfig; + let getPricingCalled; + + beforeEach(function () { + //Mock VastLoader for test purpose + window.com = { + stickyadstv : { + vast : { + VastLoader : function(){ + this.getVast = function(){ + return { + getPricing : function(){ + getPricingCalled = true; + return {currency:"USD", price: 4.000} + } + }; + }; + + this.load = function(config, listener){ + loadConfig = config; + listener.onSuccess(); + }; + } + }, + screenroll : { + getPlayerSize: function(){ + return "123x456"; + } + } + } + }; + + adapter.getBid(bidderRequest.bids[0], function(bidObject){ + bidResponse = bidObject; + }); + }); + + afterEach(function() { + delete window.com.stickyadstv.vast.VastLoader; + delete window.com.stickyadstv.vast; + delete window.com.stickyadstv.screenroll; + delete window.com.stickyadstv; + }); + + it('should have returned a valid bidObject', function () { + + expect(bidResponse).to.have.property('cpm', 4.000); + expect(bidResponse).to.have.property('ad', ""); + expect(bidResponse).to.have.property('bidderCode', "stickyadstv"); + expect(bidResponse).to.have.property('currencyCode', "USD"); + expect(bidResponse).to.have.property('width', 300); + expect(bidResponse).to.have.property('height', 250); + expect(bidResponse.getStatusCode()).to.equal(1); + }); + + it('should have called load with proper config', function () { + + expect(loadConfig).to.have.property('playerSize', "123x456"); + expect(loadConfig).to.have.property('zoneId', "2003"); + + }); + + it('should have called getPricing', function () { + + expect(getPricingCalled).to.equal(true); + + }); + }); + + describe('formatBidObject', function () { + + it('should create a valid bid object', function () { + let result = adapter.formatBidObject("", true, {currency:"EUR",price:"1.2345"}, "
sample
", 200, 300); + + expect(result).to.have.property('cpm', '1.2345'); + expect(result).to.have.property('ad', "
sample
"); + expect(result).to.have.property('bidderCode', "stickyadstv"); + expect(result).to.have.property('currencyCode', "EUR"); + expect(result).to.have.property('width', 200); + expect(result).to.have.property('height', 300); + expect(result.getStatusCode()).to.equal(1); + }); + + it('should create a invalid bid object because price is not defined', function () { + let result = adapter.formatBidObject("", true, null, "
sample
", 200, 300); + + expect(result).to.have.property('bidderCode', "stickyadstv"); + expect(result.getStatusCode()).to.equal(2); + }); + + it('should create a invalid bid object', function () { + let result = adapter.formatBidObject("", false, {currency:"EUR",price:"1.2345"}, "
sample
", 200, 300); + + expect(result).to.have.property('bidderCode', "stickyadstv"); + expect(result.getStatusCode()).to.equal(2); + }); + }); + + describe('formatAdHTML', function () { + + it('should create an inBanner ad format', function () { + let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{}}, [200,300]); + + expect(result).to.equal('
'); + }); + + it('should create an intext ad format', function () { + let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{format:"intext-roll", auto:"v2", smartPlay:"true"}}, [200,300]); + + expect(result).to.equal(''); + }); + + it('should create a screenroll ad format', function () { + let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{format:"screen-roll", smartPlay:"true"}}, [200,300]); + + expect(result).to.equal(''); + }); + }); + + describe('getBiggerSize', function () { + + it('should returns the bigger size', function () { + let result = adapter.getBiggerSize([[1,4000],[4000,1],[200,300],[0,0]]); + + expect(result[0]).to.equal(200); + expect(result[1]).to.equal(300); + }); + }); + + describe('top most window', function () { + + it('should returns the top most window', function () { + let result = adapter.getTopMostWindow(); + + expect(result).to.equal(window.top); + }); + }); + +}); \ No newline at end of file diff --git a/test/spec/adapters/thoughtleadr_spec.js b/test/spec/adapters/thoughtleadr_spec.js new file mode 100644 index 00000000000..67be54f3aef --- /dev/null +++ b/test/spec/adapters/thoughtleadr_spec.js @@ -0,0 +1,176 @@ +"use strict"; +var chai_1 = require("chai"); +var ta = require("../../../src/adapters/thoughtleadr"); +var adloader = require("../../../src/adloader"); +var bidfactory = require("../../../src/bidfactory"); +var Adapter = ta; + +function setupResponse(resp) { + var stub = sinon.stub(); + window.tldr = { + requestPrebid: stub.returns({ + then: function (cb) { + return cb(resp); + } + }) + }; + return stub; +} + +describe("thoughtleadr adapter tests", function () { + var sandbox; + var adapter; + var request; + var loadScript; + var createBid; + var tldrRequestPrebid; + + before(function () { + sandbox = sinon.sandbox.create(); + }); + + beforeEach(function () { + loadScript = sandbox.stub(adloader, "loadScript"); + createBid = sandbox.spy(bidfactory, "createBid"); + adapter = new Adapter(); + loadScript.reset(); + request = { + bidderCode: "thoughtleadr", + bids: [{ + bidder: "thoughtleadr", + placementCode: "abc-123", + sizes: [[300, 250], [400, 400]], + params: { + placementId: "test-placement" + } + }] + }; + }); + + afterEach(function () { + adapter.stopListen(); + delete window.tldr; + sandbox.restore(); + }); + + describe("callBids", function () { + + beforeEach(function () { + tldrRequestPrebid = setupResponse({}); + }); + + it("should request page.js from cdn if there wasn't before", function () { + delete window.tldr; + adapter.callBids(request); + chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal("//cdn.thoughtleadr.com/v4/page.js"); + }); + + it("should use window.tldr.config.root_url", function () { + window.tldr = { + config: { + root_url: "http://example.loc/" + } + }; + adapter.callBids(request); + chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal("http://example.loc/page.js"); + }); + + it("should not request page.js if api is present", function () { + adapter.callBids(request); + chai_1.expect(loadScript.notCalled).to.be.ok; + }); + }); + + describe("handleBids", function () { + + beforeEach(function () { + tldrRequestPrebid = setupResponse({}); + }); + + it("should filter invalid bids", function () { + request.bids.unshift({ + bidder: "thoughtleadr", + placementCode: "abc-123", + sizes: [[300, 250], [400, 400]], + params: {} + }); + request.bids.push({ + bidder: "thoughtleadr", + placementCode: "abc-123", + sizes: [[300, 250], [400, 400]], + params: { + incorrectParam: 123 + } + }); + var requestPlacement = sinon.spy(adapter, "requestPlacement"); + adapter.callBids(request); + chai_1.expect(requestPlacement.callCount).to.be.equal(1); + chai_1.expect(requestPlacement.getCall(0).args[0]).to.be.equal(request.bids[1]); + }); + }); + + describe("requestPlacement", function () { + + beforeEach(function () { + tldrRequestPrebid = setupResponse({ + config: { + abc: 567 + }, + bid: { + code: 1, + cpm: 12, + ad: "asd" + } + }); + }); + + it("should made request through page.js api", function () { + adapter.callBids(request); + chai_1.expect(tldrRequestPrebid.callCount).to.be.equal(1); + chai_1.expect(tldrRequestPrebid.firstCall.args[0]).to.be.equal(request.bids[0].params.placementId); + chai_1.expect(tldrRequestPrebid.firstCall.args[1]).to.be.length(36); + }); + + it("should call bidfactory.createBid with code 1 if ad is ok", function () { + var bid = request.bids[0]; + adapter.requestPlacement(bid); + chai_1.expect(createBid.callCount).to.be.equal(1); + chai_1.expect(createBid.firstCall.args[0]).to.be.equal(1); + }); + + it("should call bidfactory.createBid with different code if ad isn't ok", function () { + var bid = request.bids[0]; + tldrRequestPrebid = setupResponse({ + config: {}, + bid: { + code: 2 + } + }); + adapter.requestPlacement(bid); + chai_1.expect(createBid.callCount).to.be.equal(1); + chai_1.expect(createBid.firstCall.args[0]).to.be.equal(2); + }); + + it.skip("should response on the postMessage request", function (done) { + var bid = request.bids[0]; + adapter.requestPlacement(bid); + var rid = tldrRequestPrebid.firstCall.args[1]; + chai_1.expect(rid).to.be.ok; + + window.addEventListener("message", function (ev) { + if (ev.data && ev.data.TLDR_RESPONSE) { + chai_1.expect(ev.data.TLDR_RESPONSE.rid).to.be.equal(rid); + chai_1.expect(JSON.stringify(ev.data.TLDR_RESPONSE.config)).to.be.equal('{"abc":567}'); + done(); + } + else if (ev.data && ev.data.TLDR_REQUEST) { + chai_1.expect(ev.data.TLDR_REQUEST.rid).to.be.equal(rid); + } + else { + throw new Error("should not be any other messages"); + } + }, false); + window.postMessage({TLDR_REQUEST: {rid: rid}}, "*"); + }); + }); +}); diff --git a/test/spec/adapters/twenga_spec.js b/test/spec/adapters/twenga_spec.js new file mode 100644 index 00000000000..141b4c4e22b --- /dev/null +++ b/test/spec/adapters/twenga_spec.js @@ -0,0 +1,120 @@ +describe("twenga adapter tests", function () { + + var urlParse = require("url-parse"); + var querystringify = require("querystringify"); + var adapter = require("src/adapters/twenga"); + var adLoader = require("src/adloader"); + var expect = require("chai").expect; + var bidmanager = require("src/bidmanager"); + var CONSTANTS = require('src/constants.json'); + + var DEFAULT_PARAMS = { + bidderCode: "twenga", + bids: [{ + bidId: "tw_abcd1234", + sizes: [[300, 250], [300, 200]], + bidder: "twenga", + params: { + placementId: "test", + siteId: 1234, + publisherId: 5678, + currency: "USD", + bidFloor: 0.5, + country: "DE" + }, + requestId: "tw_efgh5678", + placementCode: "tw_42" + }] + }; + + var BID_RESPONSE = { + result: { + cpm: 10000, + width: 300, + height: 250, + ad: "//rtb.t.c4tw.net", + creative_id: "test" + }, + callback_uid: "tw_abcd1234" + }; + + it("sets url parameters", function () { + var stubLoadScript = sinon.stub(adLoader, "loadScript"); + + adapter().callBids(DEFAULT_PARAMS); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal("rtb.t.c4tw.net"); + expect(parsedBidUrl.pathname).to.equal("/Bid"); + + expect(parsedBidUrlQueryString).to.have.property("s").and.to.equal("h"); + expect(parsedBidUrlQueryString).to.have.property("callback").and.to.equal("$$PREBID_GLOBAL$$.handleTwCB"); + expect(parsedBidUrlQueryString).to.have.property("callback_uid").and.to.equal("tw_abcd1234"); + expect(parsedBidUrlQueryString).to.have.property("id").and.to.equal("test"); + + stubLoadScript.restore(); + }); + + var stringToFunction = function (s) { + var scope = global; + var scopeSplit = s.split('.'); + for (var i = 0; i < scopeSplit.length - 1; i++) { + scope = scope[scopeSplit[i]]; + if (scope == undefined) return; + } + return scope[scopeSplit[scopeSplit.length - 1]]; + }; + + it("creates an empty bid response if no bids", function() { + var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + var callback = stringToFunction(parsedBidUrlQueryString.callback); + expect(callback).to.exist.and.to.be.a('function'); + callback(undefined); + }); + var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); + + adapter.createNew().callBids(DEFAULT_PARAMS); + + expect(stubAddBidResponse.getCall(0)).to.be.null; + + stubAddBidResponse.restore(); + stubLoadScript.restore(); + }); + + it("creates a bid response if bid is returned", function() { + var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + $$PREBID_GLOBAL$$._bidsRequested. + push({ bidderCode: DEFAULT_PARAMS.bidderCode, + bids: [{ bidId: parsedBidUrlQueryString.callback_uid, + placementCode: DEFAULT_PARAMS.bids[0].placementCode }]}); + + var callback = stringToFunction(parsedBidUrlQueryString.callback); + expect(callback).to.exist.and.to.be.a('function'); + callback(BID_RESPONSE); + }); + var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); + + adapter.createNew().callBids(DEFAULT_PARAMS); + + var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; + + expect(bidResponseAd).to.have.property("cpm").and.to.equal(BID_RESPONSE.result.cpm / 10000); + expect(bidResponseAd).to.have.property("adUrl").and.to.equal(BID_RESPONSE.result.ad); + expect(bidResponseAd).to.have.property("width").and.to.equal(BID_RESPONSE.result.width); + expect(bidResponseAd).to.have.property("height").and.to.equal(BID_RESPONSE.result.height); + + stubAddBidResponse.restore(); + stubLoadScript.restore(); + }); +}); diff --git a/test/spec/adapters/vertamedia_spec.js b/test/spec/adapters/vertamedia_spec.js new file mode 100644 index 00000000000..2b6e9e466e4 --- /dev/null +++ b/test/spec/adapters/vertamedia_spec.js @@ -0,0 +1,147 @@ +import { expect } from 'chai'; +import Adapter from 'src/adapters/vertamedia'; +import bidmanager from 'src/bidmanager'; + +const ENDPOINT = 'http://rtb.vertamedia.com/hb/?aid=22489&w=640&h=480&domain=localhost'; + +const REQUEST = { + "bidderCode": "vertamedia", + "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6", + "bidderRequestId": "7101db09af0db2", + "bids": [ + { + "bidder": "vertamedia", + "params": { + aid: 22489, + placementId: '123456' + }, + "placementCode": "/19968336/header-bid-tag1", + "sizes": [640, 480], + "bidId": "84ab500420319d", + "bidderRequestId": "7101db09af0db2", + "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6" + } + ], + "start": 1469479810130 +}; +var RESPONSE = { + "source": { + "aid": 22489, + "pubId": 18016, + "sid": "0" + }, + "bids": [ + { + "cmpId": 9541, + "cpm": 4.5, + "url": "http://rtb.vertamedia.com/vast?adid=BFDB9CC0038AD918", + "cur": "USD" + } + ] +}; + + +describe('VertamediaAdater', () => { + + let adapter; + + beforeEach(() => adapter = Adapter.createNew()); + + describe('request function', () => { + + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('requires paramters to make request', () => { + adapter.callBids({}); + expect(requests).to.be.empty; + }); + + it('requires member && invCode', () => { + let backup = REQUEST.bids[0].params; + REQUEST.bids[0].params = {member: 1234}; + adapter.callBids(REQUEST); + expect(requests).to.be.empty; + REQUEST.bids[0].params = backup; + }); + + + it('sends bid request to ENDPOINT via POST', () => { + adapter.callBids(REQUEST); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('GET'); + }); + + }); + + describe('response handler', () => { + + let server; + + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(bidmanager, 'addBidResponse'); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + }); + + it('registers bids', () => { + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('cpm', 4.5); + }); + + it('handles nobid responses', () => { + server.respondWith(JSON.stringify({ + aid: 356465468, + w: 640, + h: 480, + domain: 'localhost' + })); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + + it('handles JSON.parse errors', () => { + server.respondWith(''); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + }); +}); diff --git a/test/spec/adapters/wideorbit_spec.js b/test/spec/adapters/wideorbit_spec.js index 36e13066c59..96d835647ee 100644 --- a/test/spec/adapters/wideorbit_spec.js +++ b/test/spec/adapters/wideorbit_spec.js @@ -65,7 +65,8 @@ describe('wideorbit adapter tests', function () { bidder: 'wideorbit', params: { PBiD: 1, - PID: 101 + PID: 101, + ReferRer: 'http://www.foo.com?param1=param1¶m2=param2' }, placementCode: 'div-gpt-ad-12345-1' }, @@ -106,6 +107,7 @@ describe('wideorbit adapter tests', function () { expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal('http://www.foo.com?param1=param1¶m2=param2'); expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('0'); @@ -184,6 +186,7 @@ describe('wideorbit adapter tests', function () { expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); @@ -260,6 +263,7 @@ describe('wideorbit adapter tests', function () { expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); diff --git a/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js b/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js index 52a3045e5c6..f4fa7e754cf 100644 --- a/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js +++ b/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js @@ -4,9 +4,9 @@ var util = require('../../common/utils.js'); module.exports = { 'adequant ad rendering' : function (browser) { browser - .url('http://localhost:9999/test/spec/e2e/gpt-examples/all_bidders_instant_load.html') + .url('http://an.localhost:9999/test/spec/e2e/gpt-examples/all_bidders_instant_load.html') .waitForElementVisible('body', 5000) - .pause(10000) + .pause(7000) .execute(util.findIframeInDiv, ['div-1'], function(result) { this.verify.equal(result.value, true, 'adequant ad not rendered'); }); diff --git a/test/spec/e2e/testcase1/dom-group/dom_spec.js b/test/spec/e2e/testcase1/dom-group/dom_spec.js index 54ff7f05eac..3ed5252bf26 100644 --- a/test/spec/e2e/testcase1/dom-group/dom_spec.js +++ b/test/spec/e2e/testcase1/dom-group/dom_spec.js @@ -19,9 +19,9 @@ module.exports = { } browser - .url('http://localhost:9999/test/spec/e2e/gpt-examples/e2e_default.html') + .url('http://an.localhost:9999/test/spec/e2e/gpt-examples/e2e_default.html') .waitForElementVisible('body', 3000) - .pause(5000) + .pause(3000) .execute(checkAdRendering2, [], function(result) { this.assert.equal(result.value, true, 'Ad of div-2 not rendered'); }); diff --git a/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js b/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js index f71838d0654..67d0306d438 100644 --- a/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js +++ b/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js @@ -6,7 +6,7 @@ module.exports = { browser .url('http://localhost:9999/test/spec/e2e/gpt-examples/gpt_default.html') .waitForElementVisible('body', 3000) - .pause(5000) + .pause(3000) .execute(function(){ if(typeof window.pbjs.bidderSettings == "undefined") { diff --git a/test/spec/integration/bug-825-truncate-bidsRequested_spec.js b/test/spec/integration/bug-825-truncate-bidsRequested_spec.js deleted file mode 100644 index 4475e746b78..00000000000 --- a/test/spec/integration/bug-825-truncate-bidsRequested_spec.js +++ /dev/null @@ -1,68 +0,0 @@ -import { equal, notEqual } from 'assert'; - -import faker from 'faker'; -import { makeAdUnit, makeBidder, makeAdSlot, makeRequest } from './faker/fixtures'; -import adaptermanager from 'src/adaptermanager'; - -function resetPrebid() { - delete window.$$PREBID_GLOBAL$$; - require('src/prebid'); -} - -let pbjsBackup; -let adUnits; -let adapters; - -describe('Bug: #825 adUnit code based refresh times out without setting targets', () => { - describe('Given a page with five ad slots has loaded and the auction is finished', () => { - - before(() => { - pbjsBackup = $$PREBID_GLOBAL$$; - - adapters = [ - makeBidder(), - makeBidder(), - makeBidder() - ]; - - adUnits = [ - makeAdUnit({ bids: adapters }), - makeAdUnit({ bids: adapters }), - makeAdUnit({ bids: adapters }), - makeAdUnit({ bids: adapters }), - makeAdUnit({ bids: adapters }) - ]; - - makeAdSlot({ code: adUnits[0].code }); - makeAdSlot({ code: adUnits[1].code }); - makeAdSlot({ code: adUnits[2].code }); - makeAdSlot({ code: adUnits[3].code }); - makeAdSlot({ code: adUnits[4].code }); - - resetPrebid(); - - adapters.forEach(adapter => { - adaptermanager.bidderRegistry[[adapter.bidder]] = { callBids: adapter.callBids }; - }); - }); - - after(() => { - window.$$PREBID_GLOBAL$$ = pbjsBackup; - }); - - describe('When the first auction completes', () => { - it('Then there will be correct number of bidder requests', () => { - var clock = sinon.useFakeTimers(); - $$PREBID_GLOBAL$$.requestBids(makeRequest({ adUnits })); - equal($$PREBID_GLOBAL$$._bidsRequested.length, 3, 'there are three bidder requests'); - var firstRequestId = $$PREBID_GLOBAL$$._bidsRequested.map(request => request.requestId).filter((value, index, array) => array.indexOf(value) === index)[0]; - $$PREBID_GLOBAL$$.requestBids(makeRequest({ adUnits: [adUnits[0]] })); - clock.tick($$PREBID_GLOBAL$$.bidderTimeout); - var nextRequestId = $$PREBID_GLOBAL$$._bidsRequested.map(request => request.requestId).filter((value, index, array) => array.indexOf(value) === index)[0]; - equal($$PREBID_GLOBAL$$._bidsRequested.length, 3, 'there are still three bidder request'); - notEqual(firstRequestId, nextRequestId, 'the request IDs have changed'); - clock.restore(); - }); - }); - }); -}); diff --git a/test/spec/loaders/adapterLoader_spec.js b/test/spec/loaders/adapterLoader_spec.js index 43e02d707e3..b68fb692110 100644 --- a/test/spec/loaders/adapterLoader_spec.js +++ b/test/spec/loaders/adapterLoader_spec.js @@ -5,7 +5,7 @@ const allAdapters = require('../../fixtures/allAdapters'); const expect = require('chai').expect; require('../../../loaders/adapterLoader'); -const defaultAdapters = ["aardvark","adblade","adbutler","adequant","adform","admedia","aol","appnexus","appnexusAst","getintent","hiromedia","indexExchange","kruxlink","komoona","openx","piximedia","pubmatic","pulsepoint","rubicon","sonobi","sovrn","springserve","triplelift","yieldbot","nginad","brightcom","wideorbit","jcm","underdogmedia","memeglobal","centro","roxot",{"appnexus":{"alias":"brealtime"}},{"appnexus":{"alias":"pagescience"}},{"appnexus":{"alias":"defymedia"}},{"appnexusAst":{"supportedMediaTypes":["video"]}}]; +const defaultAdapters = ["aardvark","adblade","adbutler","adequant","adform","admedia","aol","appnexus","appnexusAst","getintent","hiromedia","indexExchange","kruxlink","komoona","openx","piximedia","pubmatic","pulsepoint","rubicon","sonobi","sovrn","springserve","thoughtleadr","triplelift","twenga","yieldbot","nginad","brightcom","wideorbit","jcm","underdogmedia","memeglobal","centro","roxot",{"appnexus":{"alias":"brealtime"}},{"appnexus":{"alias":"pagescience"}},{"appnexus":{"alias":"defymedia"}},{"appnexusAst":{"supportedMediaTypes":["video"]}}]; const input = `/** INSERT ADAPTERS - DO NOT EDIT OR REMOVE */ /** END INSERT ADAPTERS */`;