diff --git a/modules/adkernelAdnBidAdapter.js b/modules/adkernelAdnBidAdapter.js index 28fb564320d..c02a0cb138f 100644 --- a/modules/adkernelAdnBidAdapter.js +++ b/modules/adkernelAdnBidAdapter.js @@ -80,7 +80,7 @@ export const spec = { code: 'adkernelAdn', - supportedMediaTypes: [VIDEO], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bidRequest) { return 'params' in bidRequest && (typeof bidRequest.params.host === 'undefined' || typeof bidRequest.params.host === 'string') && diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index 016cc5794fb..c3f34274692 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -16,7 +16,7 @@ export const spec = { code: 'adkernel', aliases: ['headbidding'], - supportedMediaTypes: [VIDEO], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bidRequest) { return 'params' in bidRequest && typeof bidRequest.params.host !== 'undefined' && 'zoneId' in bidRequest.params && !isNaN(Number(bidRequest.params.zoneId)); diff --git a/modules/adxcgBidAdapter.js b/modules/adxcgBidAdapter.js index 44b1f381bbe..91bf0746afc 100644 --- a/modules/adxcgBidAdapter.js +++ b/modules/adxcgBidAdapter.js @@ -1,7 +1,7 @@ import * as utils from 'src/utils'; import * as url from 'src/url'; import {registerBidder} from 'src/adapters/bidderFactory'; -import {NATIVE, VIDEO} from 'src/mediaTypes'; +import {BANNER, NATIVE, VIDEO} from 'src/mediaTypes'; /** * Adapter for requesting bids from adxcg.net @@ -9,7 +9,7 @@ import {NATIVE, VIDEO} from 'src/mediaTypes'; */ const BIDDER_CODE = 'adxcg'; -const SUPPORTED_AD_TYPES = [VIDEO, NATIVE]; +const SUPPORTED_AD_TYPES = [BANNER, VIDEO, NATIVE]; const SOURCE = 'pbjs10'; export const spec = { code: BIDDER_CODE, diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 21af777bdc5..6e5d4820ee1 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -1,13 +1,12 @@ import { Renderer } from 'src/Renderer'; import * as utils from 'src/utils'; import { registerBidder } from 'src/adapters/bidderFactory'; -import { NATIVE, VIDEO } from 'src/mediaTypes'; +import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes'; import find from 'core-js/library/fn/array/find'; import includes from 'core-js/library/fn/array/includes'; const BIDDER_CODE = 'appnexus'; const URL = '//ib.adnxs.com/ut/v3/prebid'; -const SUPPORTED_AD_TYPES = ['banner', 'video', 'native']; const VIDEO_TARGETING = ['id', 'mimes', 'minduration', 'maxduration', 'startdelay', 'skippable', 'playback_method', 'frameworks']; const USER_PARAMS = ['age', 'external_uid', 'segments', 'gender', 'dnt', 'language']; @@ -31,7 +30,7 @@ const SOURCE = 'pbjs'; export const spec = { code: BIDDER_CODE, aliases: ['appnexusAst', 'brealtime', 'pagescience', 'defymedia', 'gourmetads', 'matomy', 'featureforward', 'oftmedia', 'districtm'], - supportedMediaTypes: [VIDEO, NATIVE], + supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** * Determines whether or not the given bid request is valid. @@ -103,7 +102,7 @@ export const spec = { serverResponse.tags.forEach(serverBid => { const rtbBid = getRtbBid(serverBid); if (rtbBid) { - if (rtbBid.cpm !== 0 && includes(SUPPORTED_AD_TYPES, rtbBid.ad_type)) { + if (rtbBid.cpm !== 0 && includes(this.supportedMediaTypes, rtbBid.ad_type)) { const bid = newBid(serverBid, rtbBid); bid.mediaType = parseMediaType(rtbBid); bids.push(bid); @@ -197,7 +196,6 @@ function newBid(serverBid, rtbBid) { width: rtbBid.rtb.video.player_width, height: rtbBid.rtb.video.player_height, vastUrl: rtbBid.rtb.video.asset_url, - descriptionUrl: rtbBid.rtb.video.asset_url, ttl: 3600 }); // This supports Outstream Video @@ -209,9 +207,9 @@ function newBid(serverBid, rtbBid) { bid.adResponse.ad = bid.adResponse.ads[0]; bid.adResponse.ad.video = bid.adResponse.ad.rtb.video; } - } else if (rtbBid.rtb['native']) { - const nativeAd = rtbBid.rtb['native']; - bid['native'] = { + } else if (rtbBid.rtb[NATIVE]) { + const nativeAd = rtbBid.rtb[NATIVE]; + bid[NATIVE] = { title: nativeAd.title, body: nativeAd.desc, cta: nativeAd.ctatext, @@ -256,6 +254,7 @@ function bidToTag(bid) { const tag = {}; tag.sizes = transformSizes(bid.sizes); tag.primary_size = tag.sizes[0]; + tag.ad_types = []; tag.uuid = bid.bidId; if (bid.params.placementId) { tag.id = parseInt(bid.params.placementId, 10); @@ -294,19 +293,24 @@ function bidToTag(bid) { tag.keywords = getKeywords(bid.params.keywords); } - if (bid.mediaType === 'native' || utils.deepAccess(bid, 'mediaTypes.native')) { - tag.ad_types = ['native']; + if (bid.mediaType === NATIVE || utils.deepAccess(bid, `mediaTypes.${NATIVE}`)) { + tag.ad_types.push(NATIVE); if (bid.nativeParams) { const nativeRequest = buildNativeRequest(bid.nativeParams); - tag['native'] = {layouts: [nativeRequest]}; + tag[NATIVE] = {layouts: [nativeRequest]}; } } - const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); + const videoMediaType = utils.deepAccess(bid, `mediaTypes.${VIDEO}`); const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - if (bid.mediaType === 'video' || (videoMediaType && context !== 'outstream')) { + if (bid.mediaType === VIDEO || videoMediaType) { + tag.ad_types.push(VIDEO); + } + + // instream gets vastUrl, outstream gets vastXml + if (bid.mediaType === VIDEO || (videoMediaType && context !== 'outstream')) { tag.require_asset_url = true; } @@ -318,6 +322,13 @@ function bidToTag(bid) { .forEach(param => tag.video[param] = bid.params.video[param]); } + if ( + (utils.isEmpty(bid.mediaType) && utils.isEmpty(bid.mediaTypes)) || + (bid.mediaType === BANNER || (bid.mediaTypes && bid.mediaTypes[BANNER])) + ) { + tag.ad_types.push(BANNER); + } + return tag; } @@ -414,12 +425,12 @@ function handleOutstreamRendererEvents(bid, id, eventName) { function parseMediaType(rtbBid) { const adType = rtbBid.ad_type; - if (adType === 'video') { - return 'video'; - } else if (adType === 'native') { - return 'native'; + if (adType === VIDEO) { + return VIDEO; + } else if (adType === NATIVE) { + return NATIVE; } else { - return 'banner'; + return BANNER; } } diff --git a/modules/audienceNetworkBidAdapter.js b/modules/audienceNetworkBidAdapter.js index 41ca539ccba..2b0e4cd8190 100644 --- a/modules/audienceNetworkBidAdapter.js +++ b/modules/audienceNetworkBidAdapter.js @@ -12,7 +12,7 @@ const code = 'audienceNetwork'; const currency = 'USD'; const method = 'GET'; const url = 'https://an.facebook.com/v2/placementbid.json'; -const supportedMediaTypes = ['video']; +const supportedMediaTypes = ['banner', 'video']; const netRevenue = true; const hb_bidder = 'fan'; diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index 1f6c4f27b77..cae64983089 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -1,6 +1,6 @@ import * as utils from 'src/utils'; import {registerBidder} from 'src/adapters/bidderFactory'; -import { VIDEO } from 'src/mediaTypes'; +import { BANNER, VIDEO } from 'src/mediaTypes'; const BIDDER_CODE = 'conversant'; const URL = '//media.msg.dotomi.com/s2s/header/24'; @@ -10,7 +10,7 @@ const VERSION = '2.2.1'; export const spec = { code: BIDDER_CODE, aliases: ['cnvr'], // short code - supportedMediaTypes: [VIDEO], + supportedMediaTypes: [BANNER, VIDEO], /** * Determines whether or not the given bid request is valid. diff --git a/modules/freewheelSSPBidAdapter.js b/modules/freewheelSSPBidAdapter.js index 64ebb36478b..632df8fe93c 100644 --- a/modules/freewheelSSPBidAdapter.js +++ b/modules/freewheelSSPBidAdapter.js @@ -190,7 +190,7 @@ var getOutstreamScript = function(bid) { export const spec = { code: BIDDER_CODE, - supportedMediaTypes: ['video'], + supportedMediaTypes: ['banner', 'video'], aliases: ['stickyadstv'], // former name for freewheel-ssp /** * Determines whether or not the given bid request is valid. diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 2c1f6f9174d..fc637cc9fff 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -28,7 +28,7 @@ export const spec = { aliases: ['pulseLite', 'pulsepointLite'], - supportedMediaTypes: ['native'], + supportedMediaTypes: ['banner', 'native'], isBidRequestValid: bid => ( !!(bid && bid.params && bid.params.cp && bid.params.ct) diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 76a9095be72..1e7762ae90d 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -73,7 +73,7 @@ utils._each(sizeMap, (item, key) => sizeMap[item] = key); export const spec = { code: 'rubicon', aliases: ['rubiconLite'], - supportedMediaTypes: ['video'], + supportedMediaTypes: ['banner', 'video'], /** * @param {object} bid * @return boolean diff --git a/modules/sekindoUMBidAdapter.js b/modules/sekindoUMBidAdapter.js index 6e4ae34bd76..09b94be967b 100644 --- a/modules/sekindoUMBidAdapter.js +++ b/modules/sekindoUMBidAdapter.js @@ -2,7 +2,7 @@ import * as utils from 'src/utils'; import {registerBidder} from 'src/adapters/bidderFactory'; export const spec = { code: 'sekindoUM', - supportedMediaTypes: ['video'], + supportedMediaTypes: ['banner', 'video'], /** * Determines whether or not the given bid request is valid. * diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index ed3cc28db32..10315241c40 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -172,8 +172,14 @@ export function newBidder(spec) { // After all the responses have come back, call done() and // register any required usersync pixels. const responses = []; - function afterAllResponses() { - done(); + function afterAllResponses(bids) { + const videoBid = bids && bids[0] && bids[0].mediaType && bids[0].mediaType === 'video'; + const cacheEnabled = config.getConfig('cache.url'); + + // video bids with cache enabled need to be cached first before they are considered done + if (!(videoBid && cacheEnabled)) { + done(); + } registerSyncs(responses); } @@ -281,7 +287,7 @@ export function newBidder(spec) { addBidUsingRequestMap(bids); } } - onResponse(); + onResponse(bids); function addBidUsingRequestMap(bid) { const bidRequest = bidRequestMap[bid.requestId]; diff --git a/src/auction.js b/src/auction.js index 2a4cc128c2a..7a6b44ca459 100644 --- a/src/auction.js +++ b/src/auction.js @@ -56,7 +56,6 @@ import { Renderer } from 'src/Renderer'; import { config } from 'src/config'; import { userSync } from 'src/userSync'; import { createHook } from 'src/hook'; -import { videoAdUnit } from 'src/video'; import find from 'core-js/library/fn/array/find'; import includes from 'core-js/library/fn/array/includes'; @@ -153,20 +152,9 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels}) return innerBidRequestId === bidRequest.bidderRequestId; }); - const nonVideoBid = request.bids.filter(videoAdUnit).length === 0; - const videoBid = request.bids.filter(videoAdUnit).length > 0; - const videoBidNoCache = videoBid && !config.getConfig('cache.url'); - const videoBidWithCache = videoBid && config.getConfig('cache.url'); - - // video bids with cache enabled need to be cached first before saying they are done - if (!videoBidWithCache) { - request.doneCbCallCount += 1; - } - - // in case of mediaType video and prebidCache enabled, call bidsBackHandler after cache is stored. - if (nonVideoBid || videoBidNoCache) { - bidsBackAll() - } + // this is done for cache-enabled video bids in tryAddVideoBids, after the cache is stored + request.doneCbCallCount += 1; + bidsBackAll(); }, 1); } @@ -379,7 +367,13 @@ export function getStandardBidderSettings() { val: function (bidResponse) { return bidResponse.source; } - } + }, + { + key: 'hb_format', + val: function (bidResponse) { + return bidResponse.mediaType; + } + }, ] } return bidder_settings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD]; diff --git a/src/constants.json b/src/constants.json index e80c118ea83..9a2639ab83f 100644 --- a/src/constants.json +++ b/src/constants.json @@ -52,7 +52,8 @@ "hb_pb", "hb_size", "hb_deal", - "hb_source" + "hb_source", + "hb_format" ], "S2S" : { "SRC" : "s2s", diff --git a/src/prebid.js b/src/prebid.js index de74f2c4d7b..45fe8323eca 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -2,8 +2,6 @@ import { getGlobal } from './prebidGlobal'; import { flatten, uniques, isGptPubadsDefined, adUnitsFilter, removeRequestId } from './utils'; -import { videoAdUnit, videoBidder, hasNonVideoBidder } from './video'; -import { nativeAdUnit, nativeBidder, hasNonNativeBidder } from './native'; import { listenMessagesFromCreative } from './secureCreatives'; import { userSync } from 'src/userSync.js'; import { loadScript } from './adloader'; @@ -298,24 +296,34 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a adUnitCodes = adUnits && adUnits.map(unit => unit.code); } - // for video-enabled adUnits, only request bids for bidders that support video - adUnits.filter(videoAdUnit).filter(hasNonVideoBidder).forEach(adUnit => { - const nonVideoBidders = adUnit.bids - .filter(bid => !videoBidder(bid)) - .map(bid => bid.bidder); - - utils.logWarn(utils.unsupportedBidderMessage(adUnit, nonVideoBidders)); - adUnit.bids = adUnit.bids.filter(videoBidder); - }); - - // for native-enabled adUnits, only request bids for bidders that support native - adUnits.filter(nativeAdUnit).filter(hasNonNativeBidder).forEach(adUnit => { - const nonNativeBidders = adUnit.bids - .filter(bid => !nativeBidder(bid)) - .map(bid => bid.bidder); - - utils.logWarn(utils.unsupportedBidderMessage(adUnit, nonNativeBidders)); - adUnit.bids = adUnit.bids.filter(nativeBidder); + /* + * for a given adunit which supports a set of mediaTypes + * and a given bidder which supports a set of mediaTypes + * a bidder is eligible to participate on the adunit + * if it supports at least one of the mediaTypes on the adunit + */ + adUnits.forEach(adUnit => { + // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present + const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || {'banner': 'banner'}); + + // get the bidder's mediaTypes + const bidders = adUnit.bids.map(bid => bid.bidder); + const bidderRegistry = adaptermanager.bidderRegistry; + + bidders.forEach(bidder => { + const adapter = bidderRegistry[bidder]; + const spec = adapter && adapter.getSpec && adapter.getSpec() + // banner is default if not specified in spec + const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; + + // check if the bidder's mediaTypes are not in the adUnit's mediaTypes + const bidderEligible = adUnitMediaTypes.some(type => bidderMediaTypes.includes(type)); + if (!bidderEligible) { + // drop the bidder from the ad unit if it's not compatible + utils.logWarn(utils.unsupportedBidderMessage(adUnit, bidder)); + adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); + } + }); }); if (!adUnits || adUnits.length === 0) { diff --git a/src/utils.js b/src/utils.js index 2d185ebe4c6..0957b4e6c8f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -832,17 +832,16 @@ export function isSlotMatchingAdUnitCode(adUnitCode) { /** * Constructs warning message for when unsupported bidders are dropped from an adunit * @param {Object} adUnit ad unit from which the bidder is being dropped - * @param {Array} unSupportedBidders arrary of bidder codes that are not compatible with the adUnit + * @param {string} bidder bidder code that is not compatible with the adUnit * @return {string} warning message to display when condition is met */ -export function unsupportedBidderMessage(adUnit, unSupportedBidders) { - const mediaType = adUnit.mediaType || Object.keys(adUnit.mediaTypes).join(', '); - const plural = unSupportedBidders.length === 1 ? 'This bidder' : 'These bidders'; +export function unsupportedBidderMessage(adUnit, bidder) { + const mediaType = Object.keys(adUnit.mediaTypes || {'banner': 'banner'}).join(', '); return ` ${adUnit.code} is a ${mediaType} ad unit - containing bidders that don't support ${mediaType}: ${unSupportedBidders.join(', ')}. - ${plural} won't fetch demand. + containing bidders that don't support ${mediaType}: ${bidder}. + This bidder won't fetch demand. `; } diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 3429087a24f..a1248030c51 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -37,6 +37,7 @@ describe('auctionmanager.js', function () { var size = '300x250'; var adId = '1adId'; var source = 'client'; + var mediatype = 'banner'; before(function () { bid.cpm = bidPriceCpm; @@ -54,6 +55,7 @@ describe('auctionmanager.js', function () { bid.bidderCode = bidderCode; bid.adId = adId; bid.source = source; + bid.mediaType = mediatype; }); it('No bidder level configuration defined - default', function () { @@ -62,7 +64,8 @@ describe('auctionmanager.js', function () { 'hb_adid': adId, 'hb_pb': bidPbMg, 'hb_size': size, - 'hb_source': source + 'hb_source': source, + 'hb_format': mediatype, }; var response = getKeyValueTargetingPairs(bidderCode, bid, CONSTANTS.GRANULARITY_OPTIONS.MEDIUM); assert.deepEqual(response, expected); @@ -100,7 +103,13 @@ describe('auctionmanager.js', function () { val: function (bidResponse) { return bidResponse.source; } - } + }, + { + key: 'hb_format', + val: function (bidResponse) { + return bidResponse.mediaType; + } + }, ] } @@ -111,7 +120,8 @@ describe('auctionmanager.js', function () { 'hb_adid': adId, 'hb_pb': bidPbHg, 'hb_size': size, - 'hb_source': source + 'hb_source': source, + 'hb_format': mediatype, }; var response = getKeyValueTargetingPairs(bidderCode, bid, CONSTANTS.GRANULARITY_OPTIONS.MEDIUM); assert.deepEqual(response, expected); @@ -154,7 +164,8 @@ describe('auctionmanager.js', function () { 'hb_adid': adId, 'hb_pb': bidPbHg, 'hb_size': size, - 'hb_source': source + 'hb_source': source, + 'hb_format': mediatype, }; var response = getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); @@ -197,7 +208,8 @@ describe('auctionmanager.js', function () { 'hb_adid': adId, 'hb_pb': bidPbMg, 'hb_size': size, - 'hb_source': source + 'hb_source': source, + 'hb_format': mediatype, }; var response = getKeyValueTargetingPairs(bidderCode, bid, CONSTANTS.GRANULARITY_OPTIONS.MEDIUM); assert.deepEqual(response, expected); @@ -362,7 +374,8 @@ describe('auctionmanager.js', function () { 'hb_adid': adId, 'hb_pb': 5.57, 'hb_size': '300x250', - 'hb_source': source + 'hb_source': source, + 'hb_format': mediatype, }; var response = getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index c95fe18c688..6b09690d17a 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -76,6 +76,30 @@ describe('AppNexusAdapter', () => { }); }); + it('should populate the ad_types array on all requests', () => { + ['banner', 'video', 'native'].forEach(type => { + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest.mediaTypes = {}; + bidRequest.mediaTypes[type] = {}; + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].ad_types).to.deep.equal([type]); + }); + }); + + it('should populate the ad_types array on outstream requests', () => { + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest.mediaTypes = {}; + bidRequest.mediaTypes.video = {context: 'outstream'}; + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].ad_types).to.deep.equal(['video']); + }); + it('sends bid request to ENDPOINT via POST', () => { const request = spec.buildRequests(bidRequests); expect(request.url).to.equal(ENDPOINT); @@ -364,7 +388,6 @@ describe('AppNexusAdapter', () => { let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result[0]).to.have.property('vastUrl'); - expect(result[0]).to.have.property('descriptionUrl'); expect(result[0]).to.have.property('mediaType', 'video'); }); diff --git a/test/spec/modules/audienceNetworkBidAdapter_spec.js b/test/spec/modules/audienceNetworkBidAdapter_spec.js index b153a58eeb0..cabcdce46f2 100644 --- a/test/spec/modules/audienceNetworkBidAdapter_spec.js +++ b/test/spec/modules/audienceNetworkBidAdapter_spec.js @@ -25,7 +25,7 @@ describe('AudienceNetwork adapter', () => { expect(code).to.equal(bidder); }); it('supportedMediaTypes', () => { - expect(supportedMediaTypes).to.deep.equal(['video']); + expect(supportedMediaTypes).to.deep.equal(['banner', 'video']); }); it('isBidRequestValid', () => { expect(isBidRequestValid).to.be.a('function'); diff --git a/test/spec/modules/conversantBidAdapter_spec.js b/test/spec/modules/conversantBidAdapter_spec.js index c99cad473a3..9f7cb3ff17d 100644 --- a/test/spec/modules/conversantBidAdapter_spec.js +++ b/test/spec/modules/conversantBidAdapter_spec.js @@ -116,8 +116,8 @@ describe('Conversant adapter tests', function() { expect(spec.code).to.equal('conversant'); expect(spec.aliases).to.be.an('array').with.lengthOf(1); expect(spec.aliases[0]).to.equal('cnvr'); - expect(spec.supportedMediaTypes).to.be.an('array').with.lengthOf(1); - expect(spec.supportedMediaTypes[0]).to.equal('video'); + expect(spec.supportedMediaTypes).to.be.an('array').with.lengthOf(2); + expect(spec.supportedMediaTypes[1]).to.equal('video'); }); it('Verify user syncs', function() { diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index cb99f1b5d98..933b65c4574 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -228,8 +228,8 @@ describe('PulsePoint Adapter Tests', () => { }); it('Verifies supported media types', () => { - expect(spec.supportedMediaTypes).to.have.lengthOf(1); - expect(spec.supportedMediaTypes[0]).to.equal('native'); + expect(spec.supportedMediaTypes).to.have.lengthOf(2); + expect(spec.supportedMediaTypes[1]).to.equal('native'); }); it('Verifies if bid request valid', () => { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index c1f7fe82252..9605babf3d9 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -897,54 +897,22 @@ describe('Unit: Prebid Module', function () { }); }); - describe.skip('#video', () => { + describe('multiformat requests', () => { let spyCallBids; let createAuctionStub; let adUnits; - before(() => { + beforeEach(() => { adUnits = [{ code: 'adUnit-code', - mediaType: 'video', + mediaTypes: { + banner: {}, + native: {}, + }, sizes: [[300, 250], [300, 600]], bids: [ {bidder: 'appnexus', params: {placementId: 'id'}}, - {bidder: 'sampleBidder', params: {placementId: 'id'}} - ] - }]; - adUnitCodes = ['adUnit-code']; - let auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: timeout}); - spyCallBids = sinon.spy(adaptermanager, 'callBids'); - createAuctionStub = sinon.stub(auctionModule, 'newAuction'); - createAuctionStub.returns(auction); - }); - - after(() => { - auctionModule.newAuction.restore(); - adaptermanager.callBids.restore(); - }); - - it('should not callBids if a video adUnit has non-video bidders', () => { - const videoAdaptersBackup = adaptermanager.videoAdapters; - adaptermanager.videoAdapters = ['appnexus']; - $$PREBID_GLOBAL$$.requestBids({adUnits}); - sinon.assert.notCalled(adaptermanager.callBids); - adaptermanager.videoAdapters = videoAdaptersBackup; - }); - }); - - describe('#video', () => { - let spyCallBids; - let createAuctionStub; - let adUnits; - - before(() => { - adUnits = [{ - code: 'adUnit-code', - mediaType: 'video', - sizes: [[300, 250], [300, 600]], - bids: [ - {bidder: 'appnexus', params: {placementId: 'id'}} + {bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}} ] }]; adUnitCodes = ['adUnit-code']; @@ -954,53 +922,32 @@ describe('Unit: Prebid Module', function () { createAuctionStub.returns(auction); }) - after(() => { + afterEach(() => { auctionModule.newAuction.restore(); adaptermanager.callBids.restore(); }); - it('should callBids if a video adUnit has all video bidders', () => { - const videoAdaptersBackup = adaptermanager.videoAdapters; - adaptermanager.videoAdapters = ['appnexus']; + it('bidders that support one of the declared formats are allowed to participate', () => { $$PREBID_GLOBAL$$.requestBids({adUnits}); sinon.assert.calledOnce(adaptermanager.callBids); - adaptermanager.videoAdapters = videoAdaptersBackup; - }); - }); - describe('#native', () => { - let spyCallBids; - let createAuctionStub; - let adUnits; + const spyArgs = adaptermanager.callBids.getCall(0); + const biddersCalled = spyArgs.args[0][0].bids; - before(() => { - adUnits = [{ - code: 'adUnit-code', - mediaType: 'native', - sizes: [[300, 250], [300, 600]], - bids: [ - {bidder: 'appnexus', params: {placementId: 'id'}}, - {bidder: 'sampleBidder', params: {placementId: 'id'}} - ] - }]; - adUnitCodes = ['adUnit-code']; - let auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: timeout}); - spyCallBids = sinon.spy(adaptermanager, 'callBids'); - createAuctionStub = sinon.stub(auctionModule, 'newAuction'); - createAuctionStub.returns(auction); + // appnexus and sampleBidder both support banner + expect(biddersCalled.length).to.equal(2); }); - after(() => { - auctionModule.newAuction.restore(); - adaptermanager.callBids.restore(); - }); + it('bidders that do not support one of the declared formats are dropped', () => { + delete adUnits[0].mediaTypes.banner; - it('should only request native bidders on native adunits', () => { - // appnexus is a native bidder, appnexus is not $$PREBID_GLOBAL$$.requestBids({adUnits}); sinon.assert.calledOnce(adaptermanager.callBids); + const spyArgs = adaptermanager.callBids.getCall(0); const biddersCalled = spyArgs.args[0][0].bids; + + // only appnexus supports native expect(biddersCalled.length).to.equal(1); }); });