From 7068e4f79040f1ea1165819cf13998ea2f5bac33 Mon Sep 17 00:00:00 2001 From: Ruslan S Date: Tue, 7 May 2024 01:53:05 +0800 Subject: [PATCH] [Smaato] Migrating to ortbConverter requests build process (#11433) - Response handling will be done separately --- modules/smaatoBidAdapter.js | 421 ++++---- test/spec/modules/smaatoBidAdapter_spec.js | 1025 +++++++++++--------- 2 files changed, 755 insertions(+), 691 deletions(-) diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index 64d8765dc04b..9a0a0f756235 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -3,10 +3,11 @@ import {find} from '../src/polyfill.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import { NATIVE_IMAGE_TYPES } from '../src/constants.js'; +import {NATIVE_IMAGE_TYPES} from '../src/constants.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; import {fill} from '../libraries/appnexusUtils/anUtils.js'; import {chunk} from '../libraries/chunk/chunk.js'; +import {ortbConverter} from '../libraries/ortbConverter/converter.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -18,134 +19,14 @@ import {chunk} from '../libraries/chunk/chunk.js'; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.8' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_2.0' +const TTL = 300; const CURRENCY = 'USD'; - -const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { - const requestTemplate = { - id: bidderRequest.bidderRequestId, - at: 1, - cur: [CURRENCY], - tmax: bidderRequest.timeout, - site: { - id: window.location.hostname, - // TODO: do the fallbacks make sense here? - domain: bidderRequest.refererInfo.domain || window.location.hostname, - page: bidderRequest.refererInfo.page || window.location.href, - ref: bidderRequest.refererInfo.ref - }, - device: { - language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', - ua: navigator.userAgent, - dnt: getDNT() ? 1 : 0, - h: screen.height, - w: screen.width - }, - regs: { - coppa: config.getConfig('coppa') === true ? 1 : 0, - ext: {} - }, - user: { - ext: {} - }, - source: { - ext: { - schain: bidRequest.schain - } - }, - ext: { - client: SMAATO_CLIENT - } - }; - - let ortb2 = bidderRequest.ortb2 || {}; - Object.assign(requestTemplate.user, ortb2.user); - Object.assign(requestTemplate.site, ortb2.site); - - deepSetValue(requestTemplate, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); - - if (bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies === true) { - deepSetValue(requestTemplate, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); - deepSetValue(requestTemplate, 'user.ext.consent', bidderRequest.gdprConsent.consentString); - } - - if (bidderRequest.uspConsent !== undefined) { - deepSetValue(requestTemplate, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } - - if (ortb2.regs?.gpp !== undefined) { - deepSetValue(requestTemplate, 'regs.ext.gpp', ortb2.regs.gpp); - deepSetValue(requestTemplate, 'regs.ext.gpp_sid', ortb2.regs.gpp_sid); - } - - if (ortb2.device?.ifa !== undefined) { - deepSetValue(requestTemplate, 'device.ifa', ortb2.device.ifa); - } - - if (ortb2.device?.geo !== undefined) { - deepSetValue(requestTemplate, 'device.geo', ortb2.device.geo); - } - - if (deepAccess(bidRequest, 'params.app')) { - if (!deepAccess(requestTemplate, 'device.geo')) { - const geo = deepAccess(bidRequest, 'params.app.geo'); - deepSetValue(requestTemplate, 'device.geo', geo); - } - if (!deepAccess(requestTemplate, 'device.ifa')) { - const ifa = deepAccess(bidRequest, 'params.app.ifa'); - deepSetValue(requestTemplate, 'device.ifa', ifa); - } - } - - const eids = deepAccess(bidRequest, 'userIdAsEids'); - if (eids && eids.length) { - deepSetValue(requestTemplate, 'user.ext.eids', eids); - } - - let requests = []; - - if (deepAccess(bidRequest, 'mediaTypes.banner')) { - const bannerRequest = Object.assign({}, requestTemplate, createBannerImp(bidRequest)); - requests.push(bannerRequest); - } - - const videoMediaType = deepAccess(bidRequest, 'mediaTypes.video'); - if (videoMediaType) { - if (videoMediaType.context === ADPOD) { - const adPodRequest = Object.assign({}, requestTemplate, createAdPodImp(bidRequest, videoMediaType)); - addOptionalAdpodParameters(adPodRequest, videoMediaType); - requests.push(adPodRequest); - } else { - const videoRequest = Object.assign({}, requestTemplate, createVideoImp(bidRequest, videoMediaType)); - requests.push(videoRequest); - } - } - - const nativeOrtbRequest = bidRequest.nativeOrtbRequest; - if (nativeOrtbRequest) { - const nativeRequest = Object.assign({}, requestTemplate, createNativeImp(bidRequest, nativeOrtbRequest)); - requests.push(nativeRequest); - } - - return requests; -} - -const buildServerRequest = (validBidRequest, data) => { - logInfo('[SMAATO] OpenRTB Request:', data); - return { - method: 'POST', - url: validBidRequest.params.endpoint || SMAATO_ENDPOINT, - data: JSON.stringify(data), - options: { - withCredentials: true, - crossOrigin: true, - } - }; -} +const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO, NATIVE]; export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO, NATIVE], + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, gvlid: 82, /** @@ -195,13 +76,30 @@ export const spec = { return true; }, - buildRequests: (validBidRequests, bidderRequest) => { + buildRequests: (bidRequests, bidderRequest) => { logInfo('[SMAATO] Client version:', SMAATO_CLIENT); - return validBidRequests.map((validBidRequest) => { - const openRtbBidRequests = buildOpenRtbBidRequest(validBidRequest, bidderRequest); - return openRtbBidRequests.map((openRtbBidRequest) => buildServerRequest(validBidRequest, openRtbBidRequest)); - }).reduce((acc, item) => item != null && acc.concat(item), []); + let requests = []; + bidRequests.forEach(bid => { + // separate requests per mediaType + SUPPORTED_MEDIA_TYPES.forEach(mediaType => { + if ((bid.mediaTypes && bid.mediaTypes[mediaType]) || (mediaType === NATIVE && bid.nativeOrtbRequest)) { + const data = converter.toORTB({bidderRequest, bidRequests: [bid], context: {mediaType}}); + requests.push({ + method: 'POST', + url: bid.params.endpoint || SMAATO_ENDPOINT, + data: JSON.stringify(data), + options: { + withCredentials: true, + crossOrigin: true, + }, + bidderRequest + }) + } + }); + }); + + return requests; }, /** * Unpack the response from the server into a list of bids. @@ -239,7 +137,7 @@ export const spec = { creativeId: bid.crid, dealId: bid.dealid || null, netRevenue: deepAccess(bid, 'ext.net', true), - currency: response.cur, + currency: CURRENCY, meta: { advertiserDomains: bid.adomain, networkName: bid.bidderName, @@ -306,6 +204,172 @@ export const spec = { } registerBidder(spec); +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: TTL, + currency: CURRENCY + }, + request(buildRequest, imps, bidderRequest, context) { + function isGdprApplicable() { + return bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies; + } + + const request = buildRequest(imps, bidderRequest, context); + const bidRequest = context.bidRequests[0]; + let siteContent; + const mediaType = context.mediaType; + if (mediaType === VIDEO) { + const videoParams = bidRequest.mediaTypes[VIDEO]; + if (videoParams.context === ADPOD) { + request.imp = createAdPodImp(request.imp[0], videoParams); + siteContent = addOptionalAdpodParameters(videoParams); + } + } + + request.at = 1; + + if (request.user) { + if (isGdprApplicable()) { + deepSetValue(request.user, 'ext.consent', bidderRequest.gdprConsent.consentString); + } + } else { + const eids = deepAccess(bidRequest, 'userIdAsEids'); + request.user = { + ext: { + consent: isGdprApplicable() ? bidderRequest.gdprConsent.consentString : null, + eids: (eids && eids.length) ? eids : null + } + } + } + + if (request.site) { + request.site.id = window.location.hostname + if (siteContent) { + request.site.content = siteContent; + } + } else { + request.site = { + id: window.location.hostname, + domain: bidderRequest.refererInfo.domain || window.location.hostname, + page: bidderRequest.refererInfo.page || window.location.href, + ref: bidderRequest.refererInfo.ref, + content: siteContent || null + } + } + deepSetValue(request.site, 'publisher.id', bidRequest.params.publisherId); + + if (request.regs) { + if (isGdprApplicable()) { + deepSetValue(request.regs, 'ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + } + if (bidderRequest.uspConsent !== undefined) { + deepSetValue(request.regs, 'ext.us_privacy', bidderRequest.uspConsent); + } + if (request.regs?.gpp) { + deepSetValue(request.regs, 'ext.gpp', request.regs.gpp); + deepSetValue(request.regs, 'ext.gpp_sid', request.regs.gpp_sid); + } + } else { + request.regs = { + coppa: config.getConfig('coppa') === true ? 1 : 0, + ext: { + gdpr: isGdprApplicable() ? bidderRequest.gdprConsent.gdprApplies ? 1 : 0 : null, + us_privacy: bidderRequest.uspConsent + } + } + } + + if (request.device) { + if (bidRequest.params.app) { + if (!deepAccess(request.device, 'geo')) { + const geo = deepAccess(bidRequest, 'params.app.geo'); + deepSetValue(request.device, 'geo', geo); + } + if (!deepAccess(request.device, 'ifa')) { + const ifa = deepAccess(bidRequest, 'params.app.ifa'); + deepSetValue(request.device, 'ifa', ifa); + } + } + } else { + request.device = { + language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + ua: navigator.userAgent, + dnt: getDNT() ? 1 : 0, + h: screen.height, + w: screen.width + } + if (!deepAccess(request.device, 'geo')) { + const geo = deepAccess(bidRequest, 'params.app.geo'); + deepSetValue(request.device, 'geo', geo); + } + if (!deepAccess(request.device, 'ifa')) { + const ifa = deepAccess(bidRequest, 'params.app.ifa'); + deepSetValue(request.device, 'ifa', ifa); + } + } + + request.source = { + ext: { + schain: bidRequest.schain + } + }; + request.ext = { + client: SMAATO_CLIENT + } + return request; + }, + + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + deepSetValue(imp, 'tagid', bidRequest.params.adbreakId || bidRequest.params.adspaceId); + if (imp.bidfloorcur && imp.bidfloorcur !== CURRENCY) { + delete imp.bidfloor; + delete imp.bidfloorcur; + } + return imp; + }, + + overrides: { + imp: { + banner(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + + if (mediaType === BANNER) { + imp.bidfloor = getBidFloor(bidRequest, BANNER, getAdUnitSizes(bidRequest)); + } + + orig(imp, bidRequest, context); + }, + + video(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + if (mediaType === VIDEO) { + const videoParams = bidRequest.mediaTypes[VIDEO]; + imp.bidfloor = getBidFloor(bidRequest, VIDEO, videoParams.playerSize); + if (videoParams.context !== ADPOD) { + deepSetValue(imp, 'video.ext', { + rewarded: videoParams.ext && videoParams.ext.rewarded ? videoParams.ext.rewarded : 0 + }) + } + } + + orig(imp, bidRequest, context); + }, + + native(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + + if (mediaType === NATIVE) { + imp.bidfloor = getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(bidRequest.nativeOrtbRequest)); + } + + orig(imp, bidRequest, context); + } + }, + } +}); + const createImgAd = (adm) => { const image = JSON.parse(adm).image; @@ -346,65 +410,6 @@ const createNativeAd = (adm) => { } }; -function createBannerImp(bidRequest) { - const adUnitSizes = getAdUnitSizes(bidRequest); - const sizes = adUnitSizes.map((size) => ({w: size[0], h: size[1]})); - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, BANNER, adUnitSizes), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - banner: { - w: sizes[0].w, - h: sizes[0].h, - format: sizes - } - }] - }; -} - -function createVideoImp(bidRequest, videoMediaType) { - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, VIDEO, videoMediaType.playerSize), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - video: { - mimes: videoMediaType.mimes, - minduration: videoMediaType.minduration, - startdelay: videoMediaType.startdelay, - linearity: videoMediaType.linearity, - w: videoMediaType.playerSize[0][0], - h: videoMediaType.playerSize[0][1], - maxduration: videoMediaType.maxduration, - skip: videoMediaType.skip, - protocols: videoMediaType.protocols, - ext: { - rewarded: videoMediaType.ext && videoMediaType.ext.rewarded ? videoMediaType.ext.rewarded : 0 - }, - skipmin: videoMediaType.skipmin, - api: videoMediaType.api - } - }] - }; -} - -function createNativeImp(bidRequest, nativeRequest) { - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(nativeRequest)), - native: { - request: JSON.stringify(nativeRequest), - ver: '1.2' - } - }] - }; -} - function getNativeMainImageSize(nativeRequest) { const mainImage = find(nativeRequest.assets, asset => asset.hasOwnProperty('img') && asset.img.type === NATIVE_IMAGE_TYPES.MAIN) if (mainImage) { @@ -418,30 +423,12 @@ function getNativeMainImageSize(nativeRequest) { return [] } -function createAdPodImp(bidRequest, videoMediaType) { - const tagid = deepAccess(bidRequest, 'params.adbreakId') +function createAdPodImp(imp, videoMediaType) { const bce = config.getConfig('adpod.brandCategoryExclusion') - let imp = { - id: bidRequest.bidId, - tagid: tagid, - bidfloor: getBidFloor(bidRequest, VIDEO, videoMediaType.playerSize), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - video: { - w: videoMediaType.playerSize[0][0], - h: videoMediaType.playerSize[0][1], - mimes: videoMediaType.mimes, - startdelay: videoMediaType.startdelay, - linearity: videoMediaType.linearity, - skip: videoMediaType.skip, - protocols: videoMediaType.protocols, - skipmin: videoMediaType.skipmin, - api: videoMediaType.api, - ext: { - context: ADPOD, - brandcategoryexclusion: bce !== undefined && bce - } - } - } + imp.video.ext = { + context: ADPOD, + brandcategoryexclusion: bce !== undefined && bce + }; const numberOfPlacements = getAdPodNumberOfPlacements(videoMediaType) let imps = fill(imp, numberOfPlacements) @@ -471,9 +458,7 @@ function createAdPodImp(bidRequest, videoMediaType) { }); } - return { - imp: imps - } + return imps } function getAdPodNumberOfPlacements(videoMediaType) { @@ -486,7 +471,7 @@ function getAdPodNumberOfPlacements(videoMediaType) { : numberOfPlacements } -const addOptionalAdpodParameters = (request, videoMediaType) => { +const addOptionalAdpodParameters = (videoMediaType) => { const content = {} if (videoMediaType.tvSeriesName) { @@ -509,7 +494,7 @@ const addOptionalAdpodParameters = (request, videoMediaType) => { } if (!isEmpty(content)) { - request.site.content = content + return content } } diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index 185dee2430fb..28fd06c4b8d2 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -1,7 +1,16 @@ import {spec} from 'modules/smaatoBidAdapter.js'; import * as utils from 'src/utils.js'; import {config} from 'src/config.js'; -import {createEidsArray} from 'modules/userId/eids.js'; + +// load modules that register ORTB processors +import 'src/prebid.js' +import 'modules/currency.js'; +import 'modules/userId/index.js'; +import 'modules/multibid/index.js'; +import 'modules/priceFloors.js'; +import 'modules/consentManagement.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/schain.js'; const ADTYPE_IMG = 'Img'; const ADTYPE_RICHMEDIA = 'Richmedia'; @@ -112,14 +121,13 @@ describe('smaatoBidAdapterTest', () => { describe('buildRequests', () => { const BANNER_OPENRTB_IMP = { - w: 300, - h: 50, format: [ { h: 50, w: 300 } - ] + ], + topframe: 0, } describe('common', () => { @@ -145,13 +153,6 @@ describe('smaatoBidAdapterTest', () => { expect(req.at).to.be.equal(1); }) - it('currency is US dollar', () => { - const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.cur).to.be.deep.equal(['USD']); - }) - it('can override endpoint', () => { const overridenEndpoint = 'https://prebid/bidder'; const updatedBidRequest = utils.deepClone(singleBannerBidRequest); @@ -178,7 +179,7 @@ describe('smaatoBidAdapterTest', () => { it('sends bidfloor when configured', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function(arg) { + singleBannerBidRequestWithFloor.getFloor = function (arg) { if (arg.currency === 'USD' && arg.mediaType === 'banner' && JSON.stringify(arg.size) === JSON.stringify([300, 50])) { @@ -202,7 +203,7 @@ describe('smaatoBidAdapterTest', () => { } } }); - singleBannerMultipleSizesBidRequestWithFloor.getFloor = function(arg) { + singleBannerMultipleSizesBidRequestWithFloor.getFloor = function (arg) { if (arg.size === '*') { return { currency: 'USD', @@ -228,7 +229,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when invalid', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return undefined; } const reqs = spec.buildRequests([singleBannerBidRequestWithFloor], defaultBidderRequest); @@ -239,7 +240,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when not a number', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return { currency: 'USD', } @@ -252,7 +253,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when wrong currency', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return { currency: 'EUR', floor: 0.123 @@ -275,6 +276,58 @@ describe('smaatoBidAdapterTest', () => { expect(req.site.publisher.id).to.equal('publisherId'); }) + it('sends correct site from ortb2', () => { + const domain = 'domain'; + const page = 'page'; + const ref = 'ref'; + const ortb2 = { + site: { + name: 'example', + domain: domain, + page: page, + ref: ref + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.id).to.exist.and.to.be.a('string'); + expect(req.site.domain).to.equal(domain); + expect(req.site.page).to.equal(page); + expect(req.site.ref).to.equal(ref); + expect(req.site.publisher.id).to.equal('publisherId'); + }) + + it('sends correct device from ortb2', () => { + const language = 'language' + const ua = 'ua' + const sua = 'sua' + const dnt = 1 + const w = 2 + const h = 3 + const ortb2 = { + device: { + language: language, + ua: ua, + sua: sua, + dnt: dnt, + w: w, + h: h + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.device.language).to.equal(language); + expect(req.device.ua).to.equal(ua); + expect(req.device.sua).to.equal(sua); + expect(req.device.dnt).to.equal(dnt); + expect(req.device.w).to.equal(w); + expect(req.device.h).to.equal(h); + }) + it('sends gdpr applies if exists', () => { const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); @@ -283,6 +336,19 @@ describe('smaatoBidAdapterTest', () => { expect(req.user.ext.consent).to.equal(CONSENT_STRING); }); + it('sends correct coppa from ortb2', () => { + const ortb2 = { + regs: { + coppa: 1 + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.regs.coppa).to.equal(1); + }) + it('sends no gdpr applies if no gdpr exists', () => { const reqs = spec.buildRequests([singleBannerBidRequest], MINIMAL_BIDDER_REQUEST); @@ -321,7 +387,7 @@ describe('smaatoBidAdapterTest', () => { }); it('sends instl if instl exists', () => { - const instl = { instl: 1 }; + const instl = {instl: 1}; const bidRequestWithInstl = Object.assign({}, singleBannerBidRequest, {ortb2Imp: instl}); const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); @@ -381,6 +447,16 @@ describe('smaatoBidAdapterTest', () => { expect(req.device.geo.lon).to.equal(9.9872); }); + it('sends user first party data when user is not defined', () => { + const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.user.gender).be.undefined; + expect(req.user.yob).to.be.undefined; + expect(req.user.keywords).to.be.undefined; + expect(req.user.ext.consent).to.equal(CONSENT_STRING); + }); + it('has no user ids', () => { const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); @@ -456,531 +532,534 @@ describe('smaatoBidAdapterTest', () => { bidderWinsCount: 0 }; - it('sends correct video imps', () => { - const reqs = spec.buildRequests([singleVideoBidRequest], defaultBidderRequest); + if (FEATURES.VIDEO) { + it('sends correct video imps', () => { + const reqs = spec.buildRequests([singleVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].id).to.be.equal('bidId'); - expect(req.imp[0].tagid).to.be.equal('adspaceId'); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].id).to.be.equal('bidId'); + expect(req.imp[0].tagid).to.be.equal('adspaceId'); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); + }); - it('sends bidfloor when configured', () => { - const singleVideoBidRequestWithFloor = Object.assign({}, singleVideoBidRequest); - singleVideoBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'video' && - JSON.stringify(arg.size) === JSON.stringify([768, 1024])) { - return { - currency: 'USD', - floor: 0.456 + it('sends bidfloor when configured', () => { + const singleVideoBidRequestWithFloor = Object.assign({}, singleVideoBidRequest); + singleVideoBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'video' && + JSON.stringify(arg.size) === JSON.stringify([768, 1024])) { + return { + currency: 'USD', + floor: 0.456 + } } } - } - const reqs = spec.buildRequests([singleVideoBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([singleVideoBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.456); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.456); + }); - it('sends instl if instl exists', () => { - const instl = { instl: 1 }; - const bidRequestWithInstl = Object.assign({}, singleVideoBidRequest, {ortb2Imp: instl}); + it('sends instl if instl exists', () => { + const instl = {instl: 1}; + const bidRequestWithInstl = Object.assign({}, singleVideoBidRequest, {ortb2Imp: instl}); - const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].instl).to.equal(1); - }); - - it('splits multi format bid requests', () => { - const combinedBannerAndVideoBidRequest = { - bidder: 'smaato', - params: { - publisherId: 'publisherId', - adspaceId: 'adspaceId' - }, - mediaTypes: { - banner: BANNER_PREBID_MEDIATYPE, - video: VIDEO_OUTSTREAM_PREBID_MEDIATYPE - }, - adUnitCode: '/19968336/header-bid-tag-0', - transactionId: 'transactionId', - sizes: [[300, 50]], - bidId: 'bidId', - bidderRequestId: 'bidderRequestId', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - }; - - const reqs = spec.buildRequests([combinedBannerAndVideoBidRequest], defaultBidderRequest); - - expect(reqs).to.have.length(2); - expect(JSON.parse(reqs[0].data).imp[0].banner).to.deep.equal(BANNER_OPENRTB_IMP); - expect(JSON.parse(reqs[0].data).imp[0].video).to.not.exist; - expect(JSON.parse(reqs[1].data).imp[0].banner).to.not.exist; - expect(JSON.parse(reqs[1].data).imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].instl).to.equal(1); + }); - describe('ad pod / long form video', () => { - describe('required parameters with requireExactDuration false', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 300; - const DURATION_RANGE = [15, 30]; - const longFormVideoBidRequest = { + it('splits multi format bid requests', () => { + const combinedBannerAndVideoBidRequest = { + bidder: 'smaato', params: { publisherId: 'publisherId', - adbreakId: ADBREAK_ID, + adspaceId: 'adspaceId' }, mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: false - } + banner: BANNER_PREBID_MEDIATYPE, + video: VIDEO_OUTSTREAM_PREBID_MEDIATYPE }, - bidId: BID_ID + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 }; - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(ADPOD_DURATION / DURATION_RANGE[0]); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].bidfloor).to.be.undefined; - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - }); + const reqs = spec.buildRequests([combinedBannerAndVideoBidRequest], defaultBidderRequest); - it('sends instl if instl exists', () => { - const instl = { instl: 1 }; - const bidRequestWithInstl = Object.assign({}, longFormVideoBidRequest, {ortb2Imp: instl}); + expect(reqs).to.have.length(2); + expect(JSON.parse(reqs[0].data).imp[0].banner).to.deep.equal(BANNER_OPENRTB_IMP); + expect(JSON.parse(reqs[0].data).imp[0].video).to.not.exist; + expect(JSON.parse(reqs[1].data).imp[0].banner).to.not.exist; + expect(JSON.parse(reqs[1].data).imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); + }); - const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + describe('ad pod / long form video', () => { + describe('required parameters with requireExactDuration false', () => { + const ADBREAK_ID = 'adbreakId'; + const ADPOD = 'adpod'; + const BID_ID = '4331'; + const W = 640; + const H = 480; + const ADPOD_DURATION = 300; + const DURATION_RANGE = [15, 30]; + const longFormVideoBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: ADBREAK_ID, + }, + mediaTypes: { + video: { + context: ADPOD, + playerSize: [[W, H]], + adPodDurationSec: ADPOD_DURATION, + durationRangeSec: DURATION_RANGE, + requireExactDuration: false + } + }, + bidId: BID_ID + }; + + it('sends required fields', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.id).to.exist; + expect(req.imp.length).to.be.equal(ADPOD_DURATION / DURATION_RANGE[0]); + expect(req.imp[0].id).to.be.equal(BID_ID); + expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[0].video.w).to.be.equal(W); + expect(req.imp[0].video.h).to.be.equal(H); + expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[0].video.sequence).to.be.equal(1); + expect(req.imp[1].id).to.be.equal(BID_ID); + expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[1].bidfloor).to.be.undefined; + expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[1].video.w).to.be.equal(W); + expect(req.imp[1].video.h).to.be.equal(H); + expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.sequence).to.be.equal(2); + }); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].instl).to.equal(1); - expect(req.imp[1].instl).to.equal(1); - }); + it('sends instl if instl exists', () => { + const instl = {instl: 1}; + const bidRequestWithInstl = Object.assign({}, longFormVideoBidRequest, {ortb2Imp: instl}); - it('sends bidfloor when configured', () => { - const longFormVideoBidRequestWithFloor = Object.assign({}, longFormVideoBidRequest); - longFormVideoBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'video' && - JSON.stringify(arg.size) === JSON.stringify([640, 480])) { - return { - currency: 'USD', - floor: 0.789 + const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].instl).to.equal(1); + expect(req.imp[1].instl).to.equal(1); + }); + + it('sends bidfloor when configured', () => { + const longFormVideoBidRequestWithFloor = Object.assign({}, longFormVideoBidRequest); + longFormVideoBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'video' && + JSON.stringify(arg.size) === JSON.stringify([640, 480])) { + return { + currency: 'USD', + floor: 0.789 + } } } - } - const reqs = spec.buildRequests([longFormVideoBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.789); - expect(req.imp[1].bidfloor).to.be.equal(0.789); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.789); + expect(req.imp[1].bidfloor).to.be.equal(0.789); + }); - it('sends brand category exclusion as true when config is set to true', () => { - config.setConfig({adpod: {brandCategoryExclusion: true}}); + it('sends brand category exclusion as true when config is set to true', () => { + config.setConfig({adpod: {brandCategoryExclusion: true}}); - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(true); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(true); + }); - it('sends brand category exclusion as false when config is set to false', () => { - config.setConfig({adpod: {brandCategoryExclusion: false}}); + it('sends brand category exclusion as false when config is set to false', () => { + config.setConfig({adpod: {brandCategoryExclusion: false}}); - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + }); - it('sends brand category exclusion as false when config is not set', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + it('sends brand category exclusion as false when config is not set', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + }); }); - }); - describe('required parameters with requireExactDuration true', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 5; - const DURATION_RANGE = [5, 15, 25]; - const longFormVideoBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: ADBREAK_ID, - }, - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: true - } - }, - bidId: BID_ID - }; - - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(DURATION_RANGE.length); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.minduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.minduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - expect(req.imp[2].id).to.be.equal(BID_ID); - expect(req.imp[2].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[2].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[2].video.w).to.be.equal(W); - expect(req.imp[2].video.h).to.be.equal(H); - expect(req.imp[2].video.minduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.maxduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.sequence).to.be.equal(3); + describe('required parameters with requireExactDuration true', () => { + const ADBREAK_ID = 'adbreakId'; + const ADPOD = 'adpod'; + const BID_ID = '4331'; + const W = 640; + const H = 480; + const ADPOD_DURATION = 5; + const DURATION_RANGE = [5, 15, 25]; + const longFormVideoBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: ADBREAK_ID, + }, + mediaTypes: { + video: { + context: ADPOD, + playerSize: [[W, H]], + adPodDurationSec: ADPOD_DURATION, + durationRangeSec: DURATION_RANGE, + requireExactDuration: true + } + }, + bidId: BID_ID + }; + + it('sends required fields', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.id).to.exist; + expect(req.imp.length).to.be.equal(DURATION_RANGE.length); + expect(req.imp[0].id).to.be.equal(BID_ID); + expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[0].video.w).to.be.equal(W); + expect(req.imp[0].video.h).to.be.equal(H); + expect(req.imp[0].video.minduration).to.be.equal(DURATION_RANGE[0]); + expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[0]); + expect(req.imp[0].video.sequence).to.be.equal(1); + expect(req.imp[1].id).to.be.equal(BID_ID); + expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[1].video.w).to.be.equal(W); + expect(req.imp[1].video.h).to.be.equal(H); + expect(req.imp[1].video.minduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.sequence).to.be.equal(2); + expect(req.imp[2].id).to.be.equal(BID_ID); + expect(req.imp[2].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[2].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[2].video.w).to.be.equal(W); + expect(req.imp[2].video.h).to.be.equal(H); + expect(req.imp[2].video.minduration).to.be.equal(DURATION_RANGE[2]); + expect(req.imp[2].video.maxduration).to.be.equal(DURATION_RANGE[2]); + expect(req.imp[2].video.sequence).to.be.equal(3); + }); }); - }); - - describe('forwarding of optional parameters', () => { - const MIMES = ['video/mp4', 'video/quicktime', 'video/3gpp', 'video/x-m4v']; - const STARTDELAY = 0; - const LINEARITY = 1; - const SKIP = 1; - const PROTOCOLS = [7]; - const SKIPMIN = 5; - const API = [7]; - const validBasicAdpodBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: 'adbreakId', - }, - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - mimes: MIMES, - startdelay: STARTDELAY, - linearity: LINEARITY, - skip: SKIP, - protocols: PROTOCOLS, - skipmin: SKIPMIN, - api: API - } - }, - bidId: 'bidId' - }; - it('sends general video fields when they are present', () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.mimes).to.eql(MIMES); - expect(req.imp[0].video.startdelay).to.be.equal(STARTDELAY); - expect(req.imp[0].video.linearity).to.be.equal(LINEARITY); - expect(req.imp[0].video.skip).to.be.equal(SKIP); - expect(req.imp[0].video.protocols).to.eql(PROTOCOLS); - expect(req.imp[0].video.skipmin).to.be.equal(SKIPMIN); - expect(req.imp[0].video.api).to.eql(API); - }); + describe('forwarding of optional parameters', () => { + const MIMES = ['video/mp4', 'video/quicktime', 'video/3gpp', 'video/x-m4v']; + const STARTDELAY = 0; + const LINEARITY = 1; + const SKIP = 1; + const PROTOCOLS = [7]; + const SKIPMIN = 5; + const API = [7]; + const validBasicAdpodBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: 'adbreakId', + }, + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + mimes: MIMES, + startdelay: STARTDELAY, + linearity: LINEARITY, + skip: SKIP, + protocols: PROTOCOLS, + skipmin: SKIPMIN, + api: API + } + }, + bidId: 'bidId' + }; + + it('sends general video fields when they are present', () => { + const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.mimes).to.eql(MIMES); + expect(req.imp[0].video.startdelay).to.be.equal(STARTDELAY); + expect(req.imp[0].video.linearity).to.be.equal(LINEARITY); + expect(req.imp[0].video.skip).to.be.equal(SKIP); + expect(req.imp[0].video.protocols).to.eql(PROTOCOLS); + expect(req.imp[0].video.skipmin).to.be.equal(SKIPMIN); + expect(req.imp[0].video.api).to.eql(API); + }); - it('sends series name when parameter is present', () => { - const SERIES_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeriesName = SERIES_NAME; + it('sends series name when parameter is present', () => { + const SERIES_NAME = 'foo' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvSeriesName = SERIES_NAME; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.series).to.be.equal(SERIES_NAME); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.series).to.be.equal(SERIES_NAME); + }); - it('sends episode name when parameter is present', () => { - const EPISODE_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeName = EPISODE_NAME; + it('sends episode name when parameter is present', () => { + const EPISODE_NAME = 'foo' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvEpisodeName = EPISODE_NAME; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.title).to.be.equal(EPISODE_NAME); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.title).to.be.equal(EPISODE_NAME); + }); - it('sends season number as string when parameter is present', () => { - const SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST = 42 - const SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST = '42' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeasonNumber = SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST; + it('sends season number as string when parameter is present', () => { + const SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST = 42 + const SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST = '42' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvSeasonNumber = SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.season).to.be.equal(SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.season).to.be.equal(SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST); + }); - it('sends episode number when parameter is present', () => { - const EPISODE_NUMBER = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeNumber = EPISODE_NUMBER; + it('sends episode number when parameter is present', () => { + const EPISODE_NUMBER = 42 + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvEpisodeNumber = EPISODE_NUMBER; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.episode).to.be.equal(EPISODE_NUMBER); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.episode).to.be.equal(EPISODE_NUMBER); + }); - it('sends content length when parameter is present', () => { - const LENGTH = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentLengthSec = LENGTH; + it('sends content length when parameter is present', () => { + const LENGTH = 42 + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentLengthSec = LENGTH; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.len).to.be.equal(LENGTH); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.len).to.be.equal(LENGTH); + }); - it('sends livestream as 1 when content mode parameter is live', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'live'; + it('sends livestream as 1 when content mode parameter is live', () => { + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentMode = 'live'; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(1); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.livestream).to.be.equal(1); + }); - it('sends livestream as 0 when content mode parameter is on-demand', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'on-demand'; + it('sends livestream as 0 when content mode parameter is on-demand', () => { + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentMode = 'on-demand'; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(0); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.livestream).to.be.equal(0); + }); - it("doesn't send any optional parameters when none are present", () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); + it('doesn\'t send any optional parameters when none are present', () => { + const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.requireExactDuration).to.not.exist; - expect(req.site.content).to.not.exist; + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.requireExactDuration).to.not.exist; + expect(req.site.content).to.not.exist; + }); }); }); - }); + } }); - describe('buildRequests for native imps', () => { - const NATIVE_OPENRTB_REQUEST = { - ver: '1.2', - assets: [ - { - id: 4, - required: 1, - img: { - type: 3, - w: 150, - h: 50, - } - }, - { - id: 2, - required: 1, - img: { - type: 2, - w: 50, - h: 50 - } - }, - { - id: 0, - required: 1, - title: { - len: 80 - } - }, - { - id: 1, - required: 1, - data: { - type: 1 - } - }, - { - id: 3, - required: 1, - data: { - type: 2 - } - }, - { - id: 5, - required: 1, - data: { - type: 3 - } - }, - { - id: 6, - required: 1, - data: { - type: 4 - } - }, - { - id: 7, - required: 1, - data: { - type: 5 - } - }, - { - id: 8, - required: 1, - data: { - type: 6 - } - }, - { - id: 9, - required: 1, - data: { - type: 7 - } - }, - { - id: 10, - required: 0, - data: { - type: 8 - } - }, - { - id: 11, - required: 1, - data: { - type: 9 - } - }, - { - id: 12, - require: 0, - data: { - type: 10 - } - }, - { - id: 13, - required: 0, - data: { - type: 11 - } - }, - { - id: 14, - required: 1, - data: { - type: 12 + if (FEATURES.NATIVE) { + describe('buildRequests for native imps', () => { + const NATIVE_OPENRTB_REQUEST = { + ver: '1.2', + assets: [ + { + id: 4, + required: 1, + img: { + type: 3, + w: 150, + h: 50, + } + }, + { + id: 2, + required: 1, + img: { + type: 2, + w: 50, + h: 50 + } + }, + { + id: 0, + required: 1, + title: { + len: 80 + } + }, + { + id: 1, + required: 1, + data: { + type: 1 + } + }, + { + id: 3, + required: 1, + data: { + type: 2 + } + }, + { + id: 5, + required: 1, + data: { + type: 3 + } + }, + { + id: 6, + required: 1, + data: { + type: 4 + } + }, + { + id: 7, + required: 1, + data: { + type: 5 + } + }, + { + id: 8, + required: 1, + data: { + type: 6 + } + }, + { + id: 9, + required: 1, + data: { + type: 7 + } + }, + { + id: 10, + required: 0, + data: { + type: 8 + } + }, + { + id: 11, + required: 1, + data: { + type: 9 + } + }, + { + id: 12, + require: 0, + data: { + type: 10 + } + }, + { + id: 13, + required: 0, + data: { + type: 11 + } + }, + { + id: 14, + required: 1, + data: { + type: 12 + } } - } - ] - }; + ] + }; - const singleNativeBidRequest = { - bidder: 'smaato', - params: { - publisherId: 'publisherId', - adspaceId: 'adspaceId' - }, - nativeOrtbRequest: NATIVE_OPENRTB_REQUEST, - adUnitCode: '/19968336/header-bid-tag-0', - transactionId: 'transactionId', - bidId: 'bidId', - bidderRequestId: 'bidderRequestId', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - }; + const singleNativeBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + nativeOrtbRequest: NATIVE_OPENRTB_REQUEST, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 + }; - it('sends correct native imps', () => { - const reqs = spec.buildRequests([singleNativeBidRequest], defaultBidderRequest); + it('sends correct native imps', () => { + const reqs = spec.buildRequests([singleNativeBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].id).to.be.equal('bidId'); - expect(req.imp[0].tagid).to.be.equal('adspaceId'); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].native.request).to.deep.equal(JSON.stringify(NATIVE_OPENRTB_REQUEST)); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].id).to.be.equal('bidId'); + expect(req.imp[0].tagid).to.be.equal('adspaceId'); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].native.request).to.deep.equal(JSON.stringify(NATIVE_OPENRTB_REQUEST)); + }); - it('sends bidfloor when configured', () => { - const singleNativeBidRequestWithFloor = Object.assign({}, singleNativeBidRequest); - singleNativeBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'native' && - JSON.stringify(arg.size) === JSON.stringify([150, 50])) { - return { - currency: 'USD', - floor: 0.123 + it('sends bidfloor when configured', () => { + const singleNativeBidRequestWithFloor = Object.assign({}, singleNativeBidRequest); + singleNativeBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'native' && + JSON.stringify(arg.size) === JSON.stringify([150, 50])) { + return { + currency: 'USD', + floor: 0.123 + } } } - } - const reqs = spec.buildRequests([singleNativeBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([singleNativeBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.123); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.123); + }); }); - }); - + } describe('in-app requests', () => { const LOCATION = { lat: 33.3, @@ -1263,7 +1342,7 @@ describe('smaatoBidAdapterTest', () => { adm = ''; break; case ADTYPE_NATIVE: - adm = JSON.stringify({ native: NATIVE_RESPONSE }) + adm = JSON.stringify({native: NATIVE_RESPONSE}) break; default: throw Error('Invalid AdType');