From 574387a7601be32a8cec38f4ed4a519b1eccf346 Mon Sep 17 00:00:00 2001 From: Dan Bogdan Date: Mon, 15 Apr 2019 15:18:39 -0400 Subject: [PATCH 1/5] addressed feedback from #3731 ticket --- modules/emx_digitalBidAdapter.js | 199 ++++-- modules/emx_digitalBidAdapter.md | 28 +- .../modules/emx_digitalBidAdapter_spec.js | 602 ++++++++++++------ 3 files changed, 563 insertions(+), 266 deletions(-) diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index c42f98d4751..b16061651c6 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -1,96 +1,155 @@ import * as utils from '../src/utils'; -import { - registerBidder -} from '../src/adapters/bidderFactory'; -import { - BANNER -} from '../src/mediaTypes'; -import { - config -} from '../src/config'; +import { registerBidder } from '../src/adapters/bidderFactory'; +import { BANNER, VIDEO } from '../src/mediaTypes'; +import { config } from '../src/config'; +import includes from 'core-js/library/fn/array/includes'; const BIDDER_CODE = 'emx_digital'; const ENDPOINT = 'hb.emxdgt.com'; -let emxAdapter = {}; +export const emxAdapter = { + validateSizes: (sizes) => { + if (!utils.isArray(sizes) || typeof sizes[0] === 'undefined') { + utils.logWarn(BIDDER_CODE + ': Sizes should be an array'); + return false; + } + return sizes.every(size => utils.isArray(size) && size.length === 2); + }, + checkVideoContext: (bid) => { + return (bid && bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context && bid.mediaTypes.video.context === 'instream'); + }, + buildBanner: (bid) => { + let sizes = []; + bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes ? sizes = bid.mediaTypes.banner.sizes : sizes = bid.sizes; + if (!emxAdapter.validateSizes(sizes)) { + utils.logWarn(BIDDER_CODE + ': could not detect mediaType banner sizes. Assigning to bid sizes instead'); + sizes = bid.sizes + } + return { + format: sizes.map((size) => { + return { + w: size[0], + h: size[1] + }; + }), + w: sizes[0][0], + h: sizes[0][1] + }; + }, + formatVideoResponse: (bidResponse, emxBid) => { + bidResponse.vastXml = emxBid.adm; + return bidResponse; + }, + buildVideo: (bid) => { + bid.params.video.h = bid.mediaTypes.video.playerSize[0][0]; + bid.params.video.w = bid.mediaTypes.video.playerSize[0][1]; + return emxAdapter.cleanProtocols(bid.params.video); + }, + cleanProtocols: (video) => { + if (video.protocols && includes(video.protocols, 7)) { + utils.logWarn(BIDDER_CODE + ': VAST 4.0 is currently not supported. This protocol has been filtered out of the request.'); + video.protocols = video.protocols.filter(protocol => protocol !== 7); + } + return video; + }, + getGdpr: (bidRequests, emxData) => { + if (bidRequests.gdprConsent) { + emxData.regs = { + ext: { + gdpr: bidRequests.gdprConsent.gdprApplies === true ? 1 : 0 + } + }; + } + if (bidRequests.gdprConsent && bidRequests.gdprConsent.gdprApplies) { + emxData.user = { + ext: { + consent: bidRequests.gdprConsent.consentString + } + }; + } -emxAdapter.validateSizes = function(sizes) { - if (!utils.isArray(sizes) || typeof sizes[0] === 'undefined') { - return false; + return emxData; } - return sizes.every(size => utils.isArray(size) && size.length === 2); -} +}; export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function (bid) { - return !!bid.params.tagid && - typeof bid.params.tagid === 'string' && - (typeof bid.params.bidfloor === 'undefined' || typeof bid.params.bidfloor === 'string') && - bid.bidder === BIDDER_CODE && - (emxAdapter.validateSizes(bid.mediaTypes.banner.sizes) || emxAdapter.validateSizes(bid.sizes)); + if (!bid || !bid.params) { + utils.logWarn(BIDDER_CODE + ': Missing bid or bid params.'); + return false; + } + + if (bid.bidder !== BIDDER_CODE) { + utils.logWarn(BIDDER_CODE + ': Must use "emx_digital" as bidder code.'); + return false; + } + + if (!bid.params.tagid || !utils.isStr(bid.params.tagid)) { + utils.logWarn(BIDDER_CODE + ': Missing tagid param or tagid present and not type String.'); + return false; + } + + if (bid.mediaTypes && bid.mediaTypes.banner) { + let sizes; + bid.mediaTypes.banner.sizes ? sizes = bid.mediaTypes.banner.sizes : sizes = bid.sizes; + if (!emxAdapter.validateSizes(sizes)) { + utils.logWarn(BIDDER_CODE + ': Missing sizes in bid'); + return false; + } + } else if (bid.mediaTypes && bid.mediaTypes.video) { + if (!emxAdapter.checkVideoContext(bid)) { + utils.logWarn(BIDDER_CODE + ': Missing video context: instream'); + return false; + } + + if (!bid.mediaTypes.video.playerSize) { + utils.logWarn(BIDDER_CODE + ': Missing video playerSize'); + return false; + } + } + + return true; }, - buildRequests: function (validBidRequests, bidRequests) { - const {host, href, protocol} = utils.getTopWindowLocation(); - let emxData = {}; + buildRequests: function (validBidRequests, bidderRequest) { + const page = bidderRequest.refererInfo.referer; let emxImps = []; - const auctionId = bidRequests.auctionId; const timeout = config.getConfig('bidderTimeout'); const timestamp = Date.now(); const url = location.protocol + '//' + ENDPOINT + ('?t=' + timeout + '&ts=' + timestamp); - const networkProtocol = protocol.indexOf('https') > -1 ? 1 : 0; + const networkProtocol = location.protocol.indexOf('https') > -1 ? 1 : 0; utils._each(validBidRequests, function (bid) { let tagId = utils.getBidIdParameter('tagid', bid.params); let bidFloor = parseFloat(utils.getBidIdParameter('bidfloor', bid.params)) || 0; - let sizes = bid.mediaTypes.banner.sizes; - if (!emxAdapter.validateSizes(sizes)) { - sizes = bid.sizes - } - let emxBid = { + let isVideo = !!bid.mediaTypes.video; + let data = { id: bid.bidId, tid: bid.transactionId, tagid: tagId, - secure: networkProtocol, - banner: { - format: sizes.map(function (size) { - return { - w: size[0], - h: size[1] - }; - }), - w: sizes[0][0], - h: sizes[0][1] - } - } + secure: networkProtocol + }; + let typeSpecifics = isVideo ? { video: emxAdapter.buildVideo(bid) } : { banner: emxAdapter.buildBanner(bid) }; + let emxBid = Object.assign(data, typeSpecifics); + if (bidFloor > 0) { emxBid.bidfloor = bidFloor } emxImps.push(emxBid); }); - emxData = { - id: auctionId, + + let emxData = { + id: bidderRequest.auctionId, imp: emxImps, site: { - domain: host, - page: href - } + domain: window.top.document.location.host, + page: page + }, + version: '1.21.1' }; - if (bidRequests.gdprConsent) { - emxData.regs = { - ext: { - gdpr: bidRequests.gdprConsent.gdprApplies === true ? 1 : 0 - } - }; - } - if (bidRequests.gdprConsent && bidRequests.gdprConsent.gdprApplies) { - emxData.user = { - ext: { - consent: bidRequests.gdprConsent.consentString - } - }; - } + + emxData = emxAdapter.getGdpr(bidderRequest, Object.assign({}, emxData)); return { method: 'POST', url: url, @@ -106,7 +165,8 @@ export const spec = { if (response.seatbid && response.seatbid.length > 0 && response.seatbid[0].bid) { response.seatbid.forEach(function (emxBid) { emxBid = emxBid.bid[0]; - emxBidResponses.push({ + let isVideo = false; + let bidResponse = { requestId: emxBid.id, cpm: emxBid.price, width: emxBid.w, @@ -115,10 +175,15 @@ export const spec = { dealId: emxBid.dealid || null, currency: 'USD', netRevenue: true, - mediaType: BANNER, - ad: decodeURIComponent(emxBid.adm), - ttl: emxBid.ttl - }); + ttl: emxBid.ttl, + ad: decodeURIComponent(emxBid.adm) + }; + if (emxBid.adm && emxBid.adm.indexOf(' -1) { + isVideo = true; + bidResponse = emxAdapter.formatVideoResponse(bidResponse, Object.assign({}, emxBid)); + } + bidResponse.mediaType = (isVideo ? VIDEO : BANNER); + emxBidResponses.push(bidResponse); }); } return emxBidResponses; diff --git a/modules/emx_digitalBidAdapter.md b/modules/emx_digitalBidAdapter.md index c9435e2f1d1..b0acdbcada8 100644 --- a/modules/emx_digitalBidAdapter.md +++ b/modules/emx_digitalBidAdapter.md @@ -8,7 +8,7 @@ Maintainer: git@emxdigital.com # Description -The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner media type only. +The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner and Video (Instream) media types only. Note: The EMX Digital adapter requires approval and implementation guidelines from the EMX team, including existing publishers that work with EMX Digital. Please reach out to your account manager or prebid@emxdigital.com for more information. @@ -23,7 +23,7 @@ var adUnits = [{ code: 'banner-div', mediaTypes: { banner: { - sizes: [ + sizes: [ [300, 250], [300, 600] } }, @@ -36,3 +36,27 @@ var adUnits = [{ }] }]; ``` + +# Video Example +``` +var adUnits = [{ + code: 'video-div', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + bids: [ + { + bidder: 'emx_digital', + params: { + tagid: '25251', + video: { + skippable: true, + playback_methods: ['auto_play_sound_off'] + } + } + }] +}]; +``` diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index 85256c20bd9..f82315a919b 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -4,167 +4,343 @@ import * as utils from 'src/utils'; import { newBidder } from 'src/adapters/bidderFactory'; describe('emx_digital Adapter', function () { - const adapter = newBidder(spec); - - describe('required function', function () { + describe('callBids', function () { + const adapter = newBidder(spec); it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); }); describe('isBidRequestValid', function () { - let bid = { - 'bidder': 'emx_digital', - 'params': { - 'tagid': '25251' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [300, 250], - [300, 600] - ] - } - }, - 'adUnitCode': 'adunit-code', - 'sizes': [ - [300, 250], - [300, 600] - ], - 'bidId': '30b31c2501de1e', - 'bidderRequestId': '22edbae3120bf6', - 'auctionId': '1d1a01234a475' - }; + describe('banner request validity', function () { + let bid = { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + let badBid = { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251' + }, + 'mediaTypes': { + 'banner': { + } + }, + 'adUnitCode': 'adunit-code', + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + let noBid = {}; + let otherBid = { + 'bidder': 'emxdigital', + 'params': { + 'tagid': '25251' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + let noMediaSizeBid = { + 'bidder': 'emxdigital', + 'params': { + 'tagid': '25251' + }, + 'mediaTypes': { + 'banner': {} + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; - it('should return true when required params found', function () { - expect(spec.isBidRequestValid(bid)).to.equal(true); + // it('should return true when required params found', function () { + // expect(spec.isBidRequestValid(bid)).to.equal(true); + // }); + + // it('bidRequest with missing bidder code', function() { + // const testBid = Object.assign({}, bid, { bidder: '' }); + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + // it('bidRequest with missing params obj', function() { + // const testBid = Object.assign({}, bid); + // delete testBid.params; + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + // it('bidRequest with missing tagid param', function() { + // const testBid = Object.assign({}, bid, { params: { tagid: '' } }); + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + // it('bidRequest with missing banner sizes', function() { + // const testBid = Object.assign({}, bid, { mediaTypes: { banner: { sizes: [] } } }); + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(badBid)).to.equal(false); + expect(spec.isBidRequestValid(noBid)).to.equal(false); + expect(spec.isBidRequestValid(otherBid)).to.equal(false); + expect(spec.isBidRequestValid(noMediaSizeBid)).to.equal(false); + }); }); - it('should contain tagid param', function () { - expect(spec.isBidRequestValid({ - bidder: 'emx_digital', - params: {}, - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [300, 600] - ] - } - } - })).to.equal(false); - expect(spec.isBidRequestValid({ - bidder: 'emx_digital', - params: { - tagid: '' + describe('video request validity', function () { + let bid = { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251', + 'video': {} }, - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [300, 600] - ] + 'mediaTypes': { + 'video': { + 'context': 'instream', + 'playerSize': [640, 480] } - } - })).to.equal(false); - expect(spec.isBidRequestValid({ - bidder: 'emx_digital', - params: { - tagid: '123' }, - mediaTypes: { - banner: { - sizes: [ - ] + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + let noInstreamBid = { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251', + 'video': { + 'protocols': [1, 7] } - } - })).to.equal(false); - expect(spec.isBidRequestValid({ - bidder: 'emxdigital', - params: { - tagid: '123' }, - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [300, 600] - ] + 'mediaTypes': { + 'video': { + 'context': 'something_random' } - } - })).to.equal(false); - expect(spec.isBidRequestValid({ - bidder: 'emx_digital', - params: { - tagid: '123' }, - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [300, 600] - ] + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(noInstreamBid)).to.equal(false); + }); + + // it('bidRequest with missing instream video context', function() { + // const testBid = Object.assign({}, bid); + // delete testBid.mediaTypes.video.context; + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + // it('bidRequest with missing video playerSize', function() { + // const testBid = Object.assign({}, bid); + // delete testBid.mediaTypes.video.playerSize; + // expect(spec.isBidRequestValid(testBid)).to.equal(false); + // }) + + it('should contain tagid param', function () { + expect(spec.isBidRequestValid({ + bidder: 'emx_digital', + params: {}, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + })).to.equal(false); + expect(spec.isBidRequestValid({ + bidder: 'emx_digital', + params: { + tagid: '' + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + })).to.equal(false); + expect(spec.isBidRequestValid({ + bidder: 'emx_digital', + params: { + tagid: '123' + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } } - } - })).to.equal(true); + })).to.equal(true); + }); }); }); + // describe('emxAdapter helper validity', function () { + // let bid = { + // 'bidder': 'emx_digital', + // 'params': { + // 'tagid': '25251', + // 'video': {} + // }, + // 'mediaTypes': { + // 'video': { + // 'context': 'instream', + // 'playerSize': [640, 480] + // } + // }, + // 'adUnitCode': 'adunit-code', + // 'sizes': [ + // [300, 250], + // [300, 600] + // ], + // 'bidId': '30b31c2501de1e', + // 'bidderRequestId': '22edbae3120bf6', + // 'auctionId': '1d1a01234a475' + // }; + // describe('validateSizes()', function() { + // it('should return correct values', function () { + // expect(emxAdapter.validateSizes([[300, 250], [160, 600]])).to.equal(true); + // expect(emxAdapter.validateSizes([])).to.equal(false); + // }) + // }) + + // describe('checkVideoContext()', function () { + // it('should return correct values', function () { + // const testBid = Object.assign({}, bid); + // expect(emxAdapter.checkVideoContext(testBid)).to.equal(true); + // const testBidWithoutVideoContext = Object.assign({}, bid); + // delete testBidWithoutVideoContext.mediaTypes.video.context; + // // eslint-disable-next-line no-unused-expressions + // expect(emxAdapter.checkVideoContext(testBidWithoutVideoContext)).to.be.undefined; + // }) + // }) + // describe('buildBanner()', function () { + // it('should return ortb format banner obj', function () { + // const testBid = Object.assign({}, bid); + // delete testBid.mediaTypes.video; + // testBid.mediaTypes.banner = { + // 'sizes': [ + // [300, 250], + // [300, 600] + // ] + // }; + // const banner = emxAdapter.buildBanner(testBid); + // expect(banner).to.exist.and.to.be.a('object'); + // expect(banner.w).to.equal(testBid.mediaTypes.banner.sizes[0][0]); + // expect(banner.h).to.equal(testBid.mediaTypes.banner.sizes[0][1]); + // expect(banner.format[0].w).to.equal(testBid.mediaTypes.banner.sizes[0][0]); + // expect(banner.format[0].h).to.equal(testBid.mediaTypes.banner.sizes[0][1]); + // expect(banner.format[1].w).to.equal(testBid.mediaTypes.banner.sizes[1][0]); + // expect(banner.format[1].h).to.equal(testBid.mediaTypes.banner.sizes[1][1]); + // }) + // }) + // describe('buildVideo()', function () { + // it('should return ortb format video obj', function () { + // const testBid = Object.assign({}, bid); + // const banner = emxAdapter.buildBanner(testBid); + // expect(banner).to.exist.and.to.be.a('object'); + // }) + // }) + // describe('cleanProtocols()', function () { + // it('should remove 7 from protocols array', function () { + // const testBid = Object.assign({}, bid); + // testBid.params.video.protocols = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + // const noVast4 = emxAdapter.cleanProtocols(testBid.params.video); + // const protocols = noVast4.protocols; + // expect(protocols).to.be.an('array').that.does.not.include(7); + // }) + // }) + // describe('getGdpr()', function () { + // const consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A=='; + // const gdprObj = emxAdapter.getGdpr({ gdprConsent: { + // 'consentString': consentString, + // 'gdprApplies': true + // } }, {}); + + // it('should return properly formatted ortb gdpr obj', function () { + // expect(gdprObj).to.exist.and.to.be.a('object'); + // expect(gdprObj.regs.ext).to.have.property('gdpr', 1); + // expect(gdprObj.user.ext).to.have.property('consent', consentString); + // }) + // }) + // }); + describe('buildRequests', function () { - const bidRequests = [{ - 'bidder': 'emx_digital', - 'params': { - 'tagid': '25251' - }, - 'adUnitCode': 'adunit-code', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [300, 250], - [300, 600] - ] - } - }, - 'sizes': [ - [300, 250], - [300, 600] - ], - 'bidId': '30b31c2501de1e', - 'bidderRequestId': '22edbae3120bf6', - 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', - 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec' - }, { - 'bidder': 'emx_digital', - 'params': { - 'tagid': '25251' - }, - 'adUnitCode': 'adunit-code', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [300, 250], - [300, 600] - ] - } - }, - 'sizes': [ - [300, 250], - [300, 600] - ], - 'bidId': '30b31c2501de1e', - 'bidderRequestId': '22edbae3120bf6', - 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', - 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec' - }]; let bidderRequest = { 'bidderCode': 'emx_digital', 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', 'bidderRequestId': '22edbae3120bf6', 'timeout': 1500, + 'refererInfo': { + 'numIframes': 0, + 'reachedTop': true, + 'referer': 'https://example.com/index.html?pbjs_debug=true' + }, + 'bids': [{ + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [300, 250], + [300, 600] + ] + } + }, + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + }] }; - bidderRequest.bids = bidRequests - - let request = spec.buildRequests(bidRequests, bidderRequest); + let request = spec.buildRequests(bidderRequest.bids, bidderRequest); it('sends bid request to ENDPOINT via POST', function () { expect(request.method).to.equal('POST'); @@ -174,107 +350,94 @@ describe('emx_digital Adapter', function () { expect(request.options.withCredentials).to.equal(true); }); - it('sends contains a properly formatted endpoint url', function () { + it('contains a properly formatted endpoint url', function () { const url = request.url.split('?'); const queryParams = url[1].split('&'); expect(queryParams[0]).to.match(new RegExp('^t=\d*', 'g')); expect(queryParams[1]).to.match(new RegExp('^ts=\d*', 'g')); }); + it('builds with bid floor', function () { + const bidRequestWithBidFloor = utils.deepClone(bidderRequest.bids); + bidRequestWithBidFloor[0].params.bidfloor = 1; + const requestWithFloor = spec.buildRequests(bidRequestWithBidFloor, bidderRequest); + const data = JSON.parse(requestWithFloor.data); + expect(data.imp[0].bidfloor).to.equal(bidRequestWithBidFloor[0].params.bidfloor); + }); + it('builds request properly', function () { const data = JSON.parse(request.data); - expect(Array.isArray(data.imp)).to.equal(true); expect(data.id).to.equal(bidderRequest.auctionId); - expect(data.imp.length).to.equal(2); + expect(data.imp.length).to.equal(1); expect(data.imp[0].id).to.equal('30b31c2501de1e'); expect(data.imp[0].tid).to.equal('d7b773de-ceaa-484d-89ca-d9f51b8d61ec'); expect(data.imp[0].tagid).to.equal('25251'); expect(data.imp[0].secure).to.equal(0); + expect(data.imp[0].vastXml).to.equal(undefined); }); - it('builds with bid floor', function() { - const bidRequestWithBidFloor = utils.deepClone(bidRequests); - bidRequestWithBidFloor[0].params.bidfloor = 1; - const requestWithFloor = spec.buildRequests(bidRequestWithBidFloor, bidderRequest); - const data = JSON.parse(requestWithFloor.data); - expect(data.imp[0].bidfloor).to.equal(bidRequestWithBidFloor[0].params.bidfloor); - }) - it('properly sends site information and protocol', function () { - let mock = sinon.stub(utils, 'getTopWindowLocation').callsFake(() => { - return { - protocol: 'https:', - host: 'example.com', - href: 'https://example.com/index.html' - }; - }); - - let request; - - request = spec.buildRequests(bidRequests, bidderRequest); + request = spec.buildRequests(bidderRequest.bids, bidderRequest); request = JSON.parse(request.data); - expect(request.site.domain).to.equal('example.com'); - expect(request.site.page).to.equal('https://example.com/index.html'); - expect(request.imp[0].secure).to.equal(1); - - mock.restore(); - }) + expect(request.site.domain).to.equal(window.top.document.location.host); + expect(decodeURIComponent(request.site.page)).to.equal(bidderRequest.refererInfo.referer); + }); it('builds correctly formatted request banner object', function () { - let request; - - let bidRequestWithBanner = utils.deepClone(bidRequests); - - request = spec.buildRequests(bidRequestWithBanner, bidderRequest); + let bidRequestWithBanner = utils.deepClone(bidderRequest.bids); + let request = spec.buildRequests(bidRequestWithBanner, bidderRequest); const data = JSON.parse(request.data); + expect(data.imp[0].video).to.equal(undefined); + expect(data.imp[0].banner).to.exist.and.to.be.a('object'); expect(data.imp[0].banner.w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]); expect(data.imp[0].banner.h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]); expect(data.imp[0].banner.format[0].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][0]); expect(data.imp[0].banner.format[0].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[0][1]); expect(data.imp[0].banner.format[1].w).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][0]); expect(data.imp[0].banner.format[1].h).to.equal(bidRequestWithBanner[0].mediaTypes.banner.sizes[1][1]); - }) + }); + + it('builds correctly formatted request video object for instream', function () { + let bidRequestWithVideo = utils.deepClone(bidderRequest.bids); + bidRequestWithVideo[0].mediaTypes = { + video: { + context: 'instream', + playerSize: [640, 480] + }, + }; + bidRequestWithVideo[0].params.video = {}; + let request = spec.buildRequests(bidRequestWithVideo, bidderRequest); + const data = JSON.parse(request.data); + expect(data.imp[0].video).to.exist.and.to.be.a('object'); + expect(data.imp[0].video.h).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][0]); + expect(data.imp[0].video.w).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][1]); + }); it('shouldn\'t contain a user obj without GDPR information', function () { - let request = spec.buildRequests(bidRequests, bidderRequest) + let request = spec.buildRequests(bidderRequest.bids, bidderRequest) request = JSON.parse(request.data) expect(request).to.not.have.property('user'); }); it('should have the right gdpr info when enabled', function () { let consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A=='; - let bidderRequest = { - 'bidderCode': 'emx_digital', - 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', - 'bidderRequestId': '22edbae3120bf6', - 'timeout': 1500, - 'gdprConsent': { - 'consentString': consentString, - 'gdprApplies': true - } + bidderRequest.gdprConsent = { + 'consentString': consentString, + 'gdprApplies': true }; - bidderRequest.bids = bidRequests - let request = spec.buildRequests(bidRequests, bidderRequest); + let request = spec.buildRequests(bidderRequest.bids, bidderRequest); request = JSON.parse(request.data) expect(request.regs.ext).to.have.property('gdpr', 1); - expect(request.user.ext).to.have.property('consent', 'OIJSZsOAFsABAB8EMXZZZZZ+A=='); + expect(request.user.ext).to.have.property('consent', consentString); }); it('should\'t contain consent string if gdpr isn\'t applied', function () { - let bidderRequest = { - 'bidderCode': 'emx_digital', - 'auctionId': 'e19f1eff-8b27-42a6-888d-9674e5a6130c', - 'bidderRequestId': '22edbae3120bf6', - 'timeout': 1500, - 'gdprConsent': { - 'gdprApplies': false - } + bidderRequest.gdprConsent = { + 'gdprApplies': false }; - bidderRequest.bids = bidRequests - let request = spec.buildRequests(bidRequests, bidderRequest); - + let request = spec.buildRequests(bidderRequest.bids, bidderRequest); request = JSON.parse(request.data) expect(request.regs.ext).to.have.property('gdpr', 0); expect(request).to.not.have.property('user'); @@ -366,25 +529,56 @@ describe('emx_digital Adapter', function () { expect(ad0.cpm).to.equal(serverResponse.seatbid[0].bid[0].price); expect(ad0.creativeId).to.equal(serverResponse.seatbid[0].bid[0].crid); expect(ad0.currency).to.equal('USD'); - expect(ad0.height).to.equal(serverResponse.seatbid[0].bid[0].h); - expect(ad0.mediaType).to.equal('banner'); expect(ad0.netRevenue).to.equal(true); expect(ad0.requestId).to.equal(serverResponse.seatbid[0].bid[0].id); expect(ad0.ttl).to.equal(300); - expect(ad0.width).to.equal(serverResponse.seatbid[0].bid[0].w); expect(ad1.ad).to.equal(serverResponse.seatbid[1].bid[0].adm); expect(ad1.cpm).to.equal(serverResponse.seatbid[1].bid[0].price); expect(ad1.creativeId).to.equal(serverResponse.seatbid[1].bid[0].crid); expect(ad1.currency).to.equal('USD'); - expect(ad1.height).to.equal(serverResponse.seatbid[1].bid[0].h); - expect(ad1.mediaType).to.equal('banner'); expect(ad1.netRevenue).to.equal(true); expect(ad1.requestId).to.equal(serverResponse.seatbid[1].bid[0].id); expect(ad1.ttl).to.equal(300); + }); + + it('returns a banner bid for non-xml creatives', function () { + let result = spec.interpretResponse({ + body: serverResponse + }); + const ad0 = result[0]; + const ad1 = result[1]; + expect(ad0.mediaType).to.equal('banner'); + expect(ad0.ad.indexOf(''; + serverResponse.seatbid[1].bid[0].adm = ''; + + let result = spec.interpretResponse({ + body: serverResponse + }); + const ad0 = result[0]; + const ad1 = result[1]; + expect(ad0.mediaType).to.equal('video'); + expect(ad0.ad.indexOf(' -1).to.equal(true); + expect(ad0.vastXml).to.equal(serverResponse.seatbid[0].bid[0].adm); + expect(ad0.ad).to.exist.and.to.be.a('string'); + expect(ad1.mediaType).to.equal('video'); + expect(ad1.ad.indexOf(' -1).to.equal(true); + expect(ad1.vastXml).to.equal(serverResponse.seatbid[1].bid[0].adm); + expect(ad1.ad).to.exist.and.to.be.a('string'); + }); it('handles nobid responses', function () { let serverResponse = { 'bids': [] @@ -396,4 +590,18 @@ describe('emx_digital Adapter', function () { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs', function() { + let syncOptionsIframe = { iframeEnabled: true }; + let syncOptionsPixel = { pixelEnabled: true }; + it('Should push the correct sync type depending on the config', function() { + let iframeSync = spec.getUserSyncs(syncOptionsIframe); + expect(iframeSync.length).to.equal(1); + expect(iframeSync[0].type).to.equal('iframe'); + + let pixelSync = spec.getUserSyncs(syncOptionsPixel); + expect(pixelSync.length).to.equal(1); + expect(pixelSync[0].type).to.equal('image'); + }); + }); }); From 1bad0e8d3e0d862ebc63a5e9b5818b7e0dad3a39 Mon Sep 17 00:00:00 2001 From: Dan Bogdan Date: Wed, 17 Apr 2019 13:24:23 -0400 Subject: [PATCH 2/5] removed commented code from emx test spec --- .../modules/emx_digitalBidAdapter_spec.js | 102 ------------------ 1 file changed, 102 deletions(-) diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index f82315a919b..cd7e88828d3 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -168,18 +168,6 @@ describe('emx_digital Adapter', function () { expect(spec.isBidRequestValid(noInstreamBid)).to.equal(false); }); - // it('bidRequest with missing instream video context', function() { - // const testBid = Object.assign({}, bid); - // delete testBid.mediaTypes.video.context; - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - - // it('bidRequest with missing video playerSize', function() { - // const testBid = Object.assign({}, bid); - // delete testBid.mediaTypes.video.playerSize; - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - it('should contain tagid param', function () { expect(spec.isBidRequestValid({ bidder: 'emx_digital', @@ -216,96 +204,6 @@ describe('emx_digital Adapter', function () { }); }); - // describe('emxAdapter helper validity', function () { - // let bid = { - // 'bidder': 'emx_digital', - // 'params': { - // 'tagid': '25251', - // 'video': {} - // }, - // 'mediaTypes': { - // 'video': { - // 'context': 'instream', - // 'playerSize': [640, 480] - // } - // }, - // 'adUnitCode': 'adunit-code', - // 'sizes': [ - // [300, 250], - // [300, 600] - // ], - // 'bidId': '30b31c2501de1e', - // 'bidderRequestId': '22edbae3120bf6', - // 'auctionId': '1d1a01234a475' - // }; - // describe('validateSizes()', function() { - // it('should return correct values', function () { - // expect(emxAdapter.validateSizes([[300, 250], [160, 600]])).to.equal(true); - // expect(emxAdapter.validateSizes([])).to.equal(false); - // }) - // }) - - // describe('checkVideoContext()', function () { - // it('should return correct values', function () { - // const testBid = Object.assign({}, bid); - // expect(emxAdapter.checkVideoContext(testBid)).to.equal(true); - // const testBidWithoutVideoContext = Object.assign({}, bid); - // delete testBidWithoutVideoContext.mediaTypes.video.context; - // // eslint-disable-next-line no-unused-expressions - // expect(emxAdapter.checkVideoContext(testBidWithoutVideoContext)).to.be.undefined; - // }) - // }) - // describe('buildBanner()', function () { - // it('should return ortb format banner obj', function () { - // const testBid = Object.assign({}, bid); - // delete testBid.mediaTypes.video; - // testBid.mediaTypes.banner = { - // 'sizes': [ - // [300, 250], - // [300, 600] - // ] - // }; - // const banner = emxAdapter.buildBanner(testBid); - // expect(banner).to.exist.and.to.be.a('object'); - // expect(banner.w).to.equal(testBid.mediaTypes.banner.sizes[0][0]); - // expect(banner.h).to.equal(testBid.mediaTypes.banner.sizes[0][1]); - // expect(banner.format[0].w).to.equal(testBid.mediaTypes.banner.sizes[0][0]); - // expect(banner.format[0].h).to.equal(testBid.mediaTypes.banner.sizes[0][1]); - // expect(banner.format[1].w).to.equal(testBid.mediaTypes.banner.sizes[1][0]); - // expect(banner.format[1].h).to.equal(testBid.mediaTypes.banner.sizes[1][1]); - // }) - // }) - // describe('buildVideo()', function () { - // it('should return ortb format video obj', function () { - // const testBid = Object.assign({}, bid); - // const banner = emxAdapter.buildBanner(testBid); - // expect(banner).to.exist.and.to.be.a('object'); - // }) - // }) - // describe('cleanProtocols()', function () { - // it('should remove 7 from protocols array', function () { - // const testBid = Object.assign({}, bid); - // testBid.params.video.protocols = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - // const noVast4 = emxAdapter.cleanProtocols(testBid.params.video); - // const protocols = noVast4.protocols; - // expect(protocols).to.be.an('array').that.does.not.include(7); - // }) - // }) - // describe('getGdpr()', function () { - // const consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A=='; - // const gdprObj = emxAdapter.getGdpr({ gdprConsent: { - // 'consentString': consentString, - // 'gdprApplies': true - // } }, {}); - - // it('should return properly formatted ortb gdpr obj', function () { - // expect(gdprObj).to.exist.and.to.be.a('object'); - // expect(gdprObj.regs.ext).to.have.property('gdpr', 1); - // expect(gdprObj.user.ext).to.have.property('consent', consentString); - // }) - // }) - // }); - describe('buildRequests', function () { let bidderRequest = { 'bidderCode': 'emx_digital', From 9a31f7347e8b73fc17aea981e7ac2ab2913e2029 Mon Sep 17 00:00:00 2001 From: Dan Bogdan Date: Thu, 18 Apr 2019 10:47:31 -0400 Subject: [PATCH 3/5] logging removed from spec --- .../modules/emx_digitalBidAdapter_spec.js | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index cd7e88828d3..ecb56fb7edb 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -84,31 +84,6 @@ describe('emx_digital Adapter', function () { 'auctionId': '1d1a01234a475' }; - // it('should return true when required params found', function () { - // expect(spec.isBidRequestValid(bid)).to.equal(true); - // }); - - // it('bidRequest with missing bidder code', function() { - // const testBid = Object.assign({}, bid, { bidder: '' }); - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - - // it('bidRequest with missing params obj', function() { - // const testBid = Object.assign({}, bid); - // delete testBid.params; - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - - // it('bidRequest with missing tagid param', function() { - // const testBid = Object.assign({}, bid, { params: { tagid: '' } }); - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - - // it('bidRequest with missing banner sizes', function() { - // const testBid = Object.assign({}, bid, { mediaTypes: { banner: { sizes: [] } } }); - // expect(spec.isBidRequestValid(testBid)).to.equal(false); - // }) - it('should return true when required params found', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); expect(spec.isBidRequestValid(badBid)).to.equal(false); From ab4f33b1edc15055dded245e8c1ae8c11323e167 Mon Sep 17 00:00:00 2001 From: Nick Colletti Date: Thu, 18 Apr 2019 16:03:25 -0400 Subject: [PATCH 4/5] flip h & w values from playerSize for video requests --- modules/emx_digitalBidAdapter.js | 4 ++-- test/spec/modules/emx_digitalBidAdapter_spec.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index b16061651c6..4bffd8e1e00 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -41,8 +41,8 @@ export const emxAdapter = { return bidResponse; }, buildVideo: (bid) => { - bid.params.video.h = bid.mediaTypes.video.playerSize[0][0]; - bid.params.video.w = bid.mediaTypes.video.playerSize[0][1]; + bid.params.video.h = bid.mediaTypes.video.playerSize[0][1]; + bid.params.video.w = bid.mediaTypes.video.playerSize[0][0]; return emxAdapter.cleanProtocols(bid.params.video); }, cleanProtocols: (video) => { diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index ecb56fb7edb..dfb11ad82cd 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -283,8 +283,8 @@ describe('emx_digital Adapter', function () { let request = spec.buildRequests(bidRequestWithVideo, bidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].video).to.exist.and.to.be.a('object'); - expect(data.imp[0].video.h).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][0]); - expect(data.imp[0].video.w).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][1]); + expect(data.imp[0].video.h).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][1]); + expect(data.imp[0].video.w).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][0]); }); it('shouldn\'t contain a user obj without GDPR information', function () { From 91f7d102e9865d7ff4781ea044f069be60b0f12e Mon Sep 17 00:00:00 2001 From: Nick Colletti Date: Mon, 20 May 2019 13:03:21 -0400 Subject: [PATCH 5/5] adding Outstream mediaType to EMX Digital --- modules/emx_digitalBidAdapter.js | 62 +++++++++++++++---- modules/emx_digitalBidAdapter.md | 4 +- .../modules/emx_digitalBidAdapter_spec.js | 48 ++++++++++++-- 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index 4bffd8e1e00..5e8271b365c 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -1,11 +1,13 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; -import { config } from '../src/config'; +import * as utils from 'src/utils'; +import { registerBidder } from 'src/adapters/bidderFactory'; +import { BANNER, VIDEO } from 'src/mediaTypes'; +import { config } from 'src/config'; +import { Renderer } from 'src/Renderer'; import includes from 'core-js/library/fn/array/includes'; const BIDDER_CODE = 'emx_digital'; const ENDPOINT = 'hb.emxdgt.com'; +const RENDERER_URL = '//js.brealtime.com/outstream/1.30.0/bundle.js'; export const emxAdapter = { validateSizes: (sizes) => { @@ -16,8 +18,8 @@ export const emxAdapter = { return sizes.every(size => utils.isArray(size) && size.length === 2); }, checkVideoContext: (bid) => { - return (bid && bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context && bid.mediaTypes.video.context === 'instream'); }, + return ((bid && bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context) && ((bid.mediaTypes.video.context === 'instream') || (bid.mediaTypes.video.context === 'outstream'))); buildBanner: (bid) => { let sizes = []; bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes ? sizes = bid.mediaTypes.banner.sizes : sizes = bid.sizes; @@ -38,20 +40,56 @@ export const emxAdapter = { }, formatVideoResponse: (bidResponse, emxBid) => { bidResponse.vastXml = emxBid.adm; + if (!emxBid.renderer && (!emxBid.mediaTypes || !emxBid.mediaTypes.video || !emxBid.mediaTypes.video.context || emxBid.mediaTypes.video.context === 'outstream')) { + bidResponse.renderer = emxAdapter.createRenderer(bidResponse, { + id: emxBid.bidId, + url: RENDERER_URL + }); + } return bidResponse; }, - buildVideo: (bid) => { - bid.params.video.h = bid.mediaTypes.video.playerSize[0][1]; - bid.params.video.w = bid.mediaTypes.video.playerSize[0][0]; - return emxAdapter.cleanProtocols(bid.params.video); - }, cleanProtocols: (video) => { if (video.protocols && includes(video.protocols, 7)) { + // not supporting VAST protocol 7 (VAST 4.0); utils.logWarn(BIDDER_CODE + ': VAST 4.0 is currently not supported. This protocol has been filtered out of the request.'); video.protocols = video.protocols.filter(protocol => protocol !== 7); } return video; }, + outstreamRender: (bid) => { + bid.renderer.push(function () { + let params = (bid && bid.params && bid.params[0] && bid.params[0].video) ? bid.params[0].video : {}; + window.emxVideoQueue = window.emxVideoQueue || []; + window.queueEmxVideo({ + id: bid.adUnitCode, + adsResponses: bid.vastXml, + options: params + }); + if (window.emxVideoReady && window.videojs) { + window.emxVideoReady(); + } + }); + }, + createRenderer: (bid, rendererParams) => { + const renderer = Renderer.install({ + id: rendererParams.id, + url: RENDERER_URL, + loaded: false + }); + try { + renderer.setRender(emxAdapter.outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return renderer; + }, + buildVideo: (bid) => { + bid.params.video = bid.params.video || {}; + bid.params.video.h = bid.mediaTypes.video.playerSize[0][0]; + bid.params.video.w = bid.mediaTypes.video.playerSize[0][1]; + return emxAdapter.cleanProtocols(bid.params.video); + }, getGdpr: (bidRequests, emxData) => { if (bidRequests.gdprConsent) { emxData.regs = { @@ -100,7 +138,7 @@ export const spec = { } } else if (bid.mediaTypes && bid.mediaTypes.video) { if (!emxAdapter.checkVideoContext(bid)) { - utils.logWarn(BIDDER_CODE + ': Missing video context: instream'); + utils.logWarn(BIDDER_CODE + ': Missing video context: instream or outstream'); return false; } @@ -146,7 +184,7 @@ export const spec = { domain: window.top.document.location.host, page: page }, - version: '1.21.1' + version: '1.30.0' }; emxData = emxAdapter.getGdpr(bidderRequest, Object.assign({}, emxData)); diff --git a/modules/emx_digitalBidAdapter.md b/modules/emx_digitalBidAdapter.md index b0acdbcada8..03ba554c5ad 100644 --- a/modules/emx_digitalBidAdapter.md +++ b/modules/emx_digitalBidAdapter.md @@ -8,7 +8,7 @@ Maintainer: git@emxdigital.com # Description -The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner and Video (Instream) media types only. +The EMX Digital adapter provides publishers with access to the EMX Marketplace. The adapter is GDPR compliant. Please note that the adapter supports Banner and Video (Instream & Outstream) media types. Note: The EMX Digital adapter requires approval and implementation guidelines from the EMX team, including existing publishers that work with EMX Digital. Please reach out to your account manager or prebid@emxdigital.com for more information. @@ -43,7 +43,7 @@ var adUnits = [{ code: 'video-div', mediaTypes: { video: { - context: 'instream', + context: 'instream', // also applicable for 'outstream' playerSize: [640, 480] } }, diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index dfb11ad82cd..170e5676f43 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -138,9 +138,32 @@ describe('emx_digital Adapter', function () { 'auctionId': '1d1a01234a475' }; + let outstreamBid = { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251', + 'video': {} + }, + 'mediaTypes': { + 'video': { + 'context': 'outstream', + 'playerSize': [640, 480] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c2501de1e', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }; + it('should return true when required params found', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); expect(spec.isBidRequestValid(noInstreamBid)).to.equal(false); + expect(spec.isBidRequestValid(outstreamBid)).to.equal(true); }); it('should contain tagid param', function () { @@ -283,8 +306,24 @@ describe('emx_digital Adapter', function () { let request = spec.buildRequests(bidRequestWithVideo, bidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].video).to.exist.and.to.be.a('object'); - expect(data.imp[0].video.h).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][1]); - expect(data.imp[0].video.w).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][0]); + expect(data.imp[0].video.h).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][0]); + expect(data.imp[0].video.w).to.equal(bidRequestWithVideo[0].mediaTypes.video.playerSize[0][1]); + }); + + it('builds correctly formatted request video object for outstream', function () { + let bidRequestWithOutstreamVideo = utils.deepClone(bidderRequest.bids); + bidRequestWithOutstreamVideo[0].mediaTypes = { + video: { + context: 'outstream', + playerSize: [640, 480] + }, + }; + bidRequestWithOutstreamVideo[0].params.video = {}; + let request = spec.buildRequests(bidRequestWithOutstreamVideo, bidderRequest); + const data = JSON.parse(request.data); + expect(data.imp[0].video).to.exist.and.to.be.a('object'); + expect(data.imp[0].video.h).to.equal(bidRequestWithOutstreamVideo[0].mediaTypes.video.playerSize[0][0]); + expect(data.imp[0].video.w).to.equal(bidRequestWithOutstreamVideo[0].mediaTypes.video.playerSize[0][1]); }); it('shouldn\'t contain a user obj without GDPR information', function () { @@ -452,6 +491,7 @@ describe('emx_digital Adapter', function () { expect(ad1.vastXml).to.equal(serverResponse.seatbid[1].bid[0].adm); expect(ad1.ad).to.exist.and.to.be.a('string'); }); + it('handles nobid responses', function () { let serverResponse = { 'bids': [] @@ -464,10 +504,10 @@ describe('emx_digital Adapter', function () { }); }); - describe('getUserSyncs', function() { + describe('getUserSyncs', function () { let syncOptionsIframe = { iframeEnabled: true }; let syncOptionsPixel = { pixelEnabled: true }; - it('Should push the correct sync type depending on the config', function() { + it('Should push the correct sync type depending on the config', function () { let iframeSync = spec.getUserSyncs(syncOptionsIframe); expect(iframeSync.length).to.equal(1); expect(iframeSync[0].type).to.equal('iframe');