From 6c85f5b699acb7abd342308d31e8fa67b0482058 Mon Sep 17 00:00:00 2001 From: Dan Bogdan <43830380+EMXDigital@users.noreply.github.com> Date: Tue, 28 May 2019 11:58:42 -0400 Subject: [PATCH] adding Outstream mediaType to EMX Digital (#3840) * addressed feedback from #3731 ticket * removed commented code from emx test spec * logging removed from spec * flip h & w values from playerSize for video requests * 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..75ce47aae0a 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,7 +18,7 @@ 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 = []; @@ -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');