From 43089c70a8209d9dccd1c418f510709e6de0c933 Mon Sep 17 00:00:00 2001 From: onlsol <48312668+onlsol@users.noreply.github.com> Date: Sat, 1 Apr 2023 01:26:14 +0200 Subject: [PATCH] DSPx bid adapter: bidder enhancement (#9674) * Dspx: improve floorprice support, dynamic mediatype handling and shared id support; add video context/renderer support and schain * kick of tests * Dspx: improve floorprice support, dynamic mediatype handling and shared id support; add video context/renderer support and schain --------- Co-authored-by: Alexander Co-authored-by: Chris Huie --- modules/dspxBidAdapter.js | 238 +++++++++++++++++++++-- test/spec/modules/dspxBidAdapter_spec.js | 197 +++++++++++++++++-- 2 files changed, 407 insertions(+), 28 deletions(-) diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js index 8850eb282b5..7606bc86d73 100644 --- a/modules/dspxBidAdapter.js +++ b/modules/dspxBidAdapter.js @@ -1,12 +1,17 @@ -import { deepAccess } from '../src/utils.js'; +import {deepAccess, getBidIdParameter, logError, logMessage, logWarn, isFn} from '../src/utils.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; +import {includes} from '../src/polyfill.js'; const BIDDER_CODE = 'dspx'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; const GVLID = 602; +const VIDEO_ORTB_PARAMS = ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', + 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', + 'api', 'companiontype', 'ext']; export const spec = { code: BIDDER_CODE, @@ -17,24 +22,34 @@ export const spec = { return !!(bid.params.placement); }, buildRequests: function(validBidRequests, bidderRequest) { + let payload = {}; return validBidRequests.map(bidRequest => { const params = bidRequest.params; - const placementId = params.placement; const rnd = Math.floor(Math.random() * 99999999999); const referrer = bidderRequest.refererInfo.page; const bidId = bidRequest.bidId; - const isDev = params.devMode || false; const pbcode = bidRequest.adUnitCode || false; // div id const auctionId = bidRequest.auctionId || false; + const isDev = params.devMode || false; let endpoint = isDev ? ENDPOINT_URL_DEV : ENDPOINT_URL; + let placementId = params.placement; + + // dev config + if (isDev && params.dev) { + endpoint = params.dev.endpoint || endpoint; + placementId = params.dev.placement || placementId; + if (params.dev.pfilter !== undefined) { + params.pfilter = params.dev.pfilter; + } + } let mediaTypesInfo = getMediaTypesInfo(bidRequest); let type = isBannerRequest(bidRequest) ? BANNER : VIDEO; let sizes = mediaTypesInfo[type]; - let payload = { + payload = { _f: 'auto', alternative: 'prebid_js', inventory_item_id: placementId, @@ -47,10 +62,6 @@ export const spec = { pbver: '$prebid.version$' }; - if (mediaTypesInfo[VIDEO] !== undefined && params.vastFormat !== undefined) { - payload.vf = params.vastFormat; - } - if (params.pfilter !== undefined) { payload.pfilter = params.pfilter; } @@ -79,11 +90,49 @@ export const spec = { payload.prebidDevMode = 1; } - if (bidRequest.userId && bidRequest.userId.netId) { - payload.did_netid = bidRequest.userId.netId; + // fill userId params + if (bidRequest.userId) { + if (bidRequest.userId.netId) { + payload.did_netid = bidRequest.userId.netId; + } + if (bidRequest.userId.id5id) { + payload.did_id5 = bidRequest.userId.id5id.uid || '0'; + if (bidRequest.userId.id5id.ext.linkType !== undefined) { + payload.did_id5_linktype = bidRequest.userId.id5id.ext.linkType; + } + } + let uId2 = deepAccess(bidRequest, 'userId.uid2.id'); + if (uId2) { + payload.did_uid2 = uId2; + } + let sharedId = deepAccess(bidRequest, 'userId.sharedid.id'); + if (sharedId) { + payload.did_sharedid = sharedId; + } + let pubcId = deepAccess(bidRequest, 'userId.pubcid'); + if (pubcId) { + payload.did_pubcid = pubcId; + } + let crumbsPubcid = deepAccess(bidRequest, 'crumbs.pubcid'); + if (crumbsPubcid) { + payload.did_cpubcid = crumbsPubcid; + } + } + + if (bidRequest.schain) { + payload.schain = bidRequest.schain; } - if (bidRequest.userId && bidRequest.userId.uid2) { - payload.did_uid2 = bidRequest.userId.uid2; + + if (payload.pfilter === undefined || !payload.pfilter.floorprice) { + let bidFloor = getBidFloor(bidRequest); + if (bidFloor > 0) { + if (payload.pfilter !== undefined) { + payload.pfilter.floorprice = bidFloor; + } else { + payload.pfilter = { 'floorprice': bidFloor }; + } + // payload.bidFloor = bidFloor; + } } if (auctionId) { @@ -94,6 +143,17 @@ export const spec = { } payload.media_types = convertMediaInfoForRequest(mediaTypesInfo); + if (mediaTypesInfo[VIDEO] !== undefined) { + payload.vctx = getVideoContext(bidRequest); + if (params.vastFormat !== undefined) { + payload.vf = params.vastFormat; + } + payload.vpl = {}; + let videoParams = deepAccess(bidRequest, 'mediaTypes.video'); + Object.keys(videoParams) + .filter(key => includes(VIDEO_ORTB_PARAMS, key)) + .forEach(key => payload.vpl[key] = videoParams[key]); + } return { method: 'GET', @@ -103,6 +163,8 @@ export const spec = { }); }, interpretResponse: function(serverResponse, bidRequest) { + logMessage('DSPx: serverResponse', serverResponse); + logMessage('DSPx: bidRequest', bidRequest); const bidResponses = []; const response = serverResponse.body; const crid = response.crid || 0; @@ -126,13 +188,33 @@ export const spec = { advertiserDomains: response.adomain || [] } }; + + if (response.vastUrl) { + bidResponse.vastUrl = response.vastUrl; + bidResponse.mediaType = 'video'; + } if (response.vastXml) { bidResponse.vastXml = response.vastXml; bidResponse.mediaType = 'video'; - } else { + } + if (response.renderer) { + bidResponse.renderer = newRenderer(bidRequest, response); + } + + if (response.videoCacheKey) { + bidResponse.videoCacheKey = response.videoCacheKey; + } + + if (response.adTag) { bidResponse.ad = response.adTag; } + if (response.bid_appendix) { + Object.keys(response.bid_appendix).forEach(fieldName => { + bidResponse[fieldName] = response.bid_appendix[fieldName]; + }); + } + bidResponses.push(bidResponse); } return bidResponses; @@ -217,12 +299,22 @@ function isVideoRequest(bid) { * Get video sizes * * @param {BidRequest} bid - Bid request generated from ad slots - * @returns {object} True if it's a video bid + * @returns {object} */ function getVideoSizes(bid) { return parseSizes(deepAccess(bid, 'mediaTypes.video.playerSize') || bid.sizes); } +/** + * Get video context + * + * @param {BidRequest} bid - Bid request generated from ad slots + * @returns {object} + */ +function getVideoContext(bid) { + return deepAccess(bid, 'mediaTypes.video.context') || 'unknown'; +} + /** * Get banner sizes * @@ -296,4 +388,120 @@ function getMediaTypesInfo(bid) { return mediaTypesInfo; } +/** + * Get Bid Floor + * @param bid + * @returns {number|*} + */ +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'EUR', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (_) { + return 0 + } +} + +/** + * Create a new renderer + * + * @param bidRequest + * @param response + * @returns {Renderer} + */ +function newRenderer(bidRequest, response) { + logMessage('DSPx: newRenderer', bidRequest, response); + const renderer = Renderer.install({ + id: response.renderer.id || response.bid_id, + url: (bidRequest.params && bidRequest.params.rendererUrl) || response.renderer.url, + config: response.renderer.options || deepAccess(bidRequest, 'renderer.options'), + loaded: false + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; +} + +/** + * Outstream Render Function + * + * @param bid + */ +function outstreamRender(bid) { + logMessage('DSPx: outstreamRender bid:', bid); + const embedCode = createOutstreamEmbedCode(bid); + try { + const inIframe = getBidIdParameter('iframe', bid.renderer.config); + if (inIframe && window.document.getElementById(inIframe).nodeName === 'IFRAME') { + const iframe = window.document.getElementById(inIframe); + let framedoc = iframe.contentDocument || (iframe.contentWindow && iframe.contentWindow.document); + framedoc.body.appendChild(embedCode); + if (typeof window.dspxRender === 'function') { + window.dspxRender(bid); + } else { + logError('[dspx][renderer] Error: dspxRender function is not found'); + } + return; + } + + const slot = getBidIdParameter('slot', bid.renderer.config) || bid.adUnitCode; + if (slot && window.document.getElementById(slot)) { + window.document.getElementById(slot).appendChild(embedCode); + if (typeof window.dspxRender === 'function') { + window.dspxRender(bid); + } else { + logError('[dspx][renderer] Error: dspxRender function is not found'); + } + } else if (slot) { + logError('[dspx][renderer] Error: slot not found'); + } + } catch (err) { + logError('[dspx][renderer] Error:' + err.message) + } +} + +/** + * create Outstream Embed Code Node + * + * @param bid + * @returns {DocumentFragment} + */ +function createOutstreamEmbedCode(bid) { + const fragment = window.document.createDocumentFragment(); + let div = window.document.createElement('div'); + div.innerHTML = deepAccess(bid, 'renderer.config.code', ""); + fragment.appendChild(div); + + // run scripts + var scripts = div.getElementsByTagName('script'); + var scriptsClone = []; + for (var idx = 0; idx < scripts.length; idx++) { + scriptsClone.push(scripts[idx]); + } + for (var i = 0; i < scriptsClone.length; i++) { + var currentScript = scriptsClone[i]; + var s = document.createElement('script'); + for (var j = 0; j < currentScript.attributes.length; j++) { + var a = currentScript.attributes[j]; + s.setAttribute(a.name, a.value); + } + s.appendChild(document.createTextNode(currentScript.innerHTML)); + currentScript.parentNode.replaceChild(s, currentScript); + } + + return fragment; +} + registerBidder(spec); diff --git a/test/spec/modules/dspxBidAdapter_spec.js b/test/spec/modules/dspxBidAdapter_spec.js index 2869385d7e7..841fc087613 100644 --- a/test/spec/modules/dspxBidAdapter_spec.js +++ b/test/spec/modules/dspxBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec } from 'modules/dspxBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import { deepClone } from '../../../src/utils'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; @@ -65,7 +66,34 @@ describe('dspxAdapter', function () { 'adUnitCode': 'testDiv1', 'userId': { 'netId': '123', - 'uid2': '456' + 'uid2': {'id': '456'}, + 'pubcid': 'e09ab6a3-ae74-4f01-b2e8-81b141d6dc61', + 'id5id': { + 'uid': 'ID5-ZHMOcvSShIBZiIth_yYh9odjNFxVEmMQ_i5TArPfWw!ID5*dtrjfV5mPLasyya5TW2IE9oVzQZwx7xRPGyAYS4hcWkAAOoxoFef4bIoREpQys8x', + 'ext': { + 'linkType': 2 + } + }, + 'sharedid': { + 'id': '01EXPPGZ9C8NKG1MTXVHV98505', + 'third': '01EXPPGZ9C8NKG1MTXVHV98505' + } + }, + 'crumbs': { + 'pubcid': 'e09ab6a3-ae74-4f01-b2e8-81b141d6dc61' + }, + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'example.com', + 'sid': '0', + 'hp': 1, + 'rid': 'bidrequestid', + 'domain': 'example.com' + } + ] } }, { @@ -111,7 +139,10 @@ describe('dspxAdapter', function () { 'mediaTypes': { 'video': { 'playerSize': [640, 480], - 'context': 'instream' + 'context': 'instream', + 'protocols': [1, 2], + 'playbackmethod': [2], + 'skip': 1 }, 'banner': { 'sizes': [ @@ -135,14 +166,53 @@ describe('dspxAdapter', function () { 'mediaTypes': { 'video': { 'playerSize': [640, 480], - 'context': 'instream' + 'context': 'instream', + 'protocols': [1, 2], + 'playbackmethod': [2], + 'skip': 1, + 'renderer': { + url: 'example.com/videoRenderer.js', + render: function (bid) { alert('test'); } + } } }, 'bidId': '30b31c1838de1e41', 'bidderRequestId': '22edbae2733bf67', 'auctionId': '1d1a030790a478', 'adUnitCode': 'testDiv4' - } + }, + { + 'bidder': 'dspx', + 'params': { + 'placement': '101', + 'devMode': true, + 'dev': { + 'endpoint': 'http://localhost', + 'placement': '107', + 'pfilter': {'test': 1} + } + }, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream', + 'mimes': ['video/mp4'], + 'protocols': [1, 2], + 'playbackmethod': [2], + 'skip': 1 + }, + 'banner': { + 'sizes': [ + [300, 250] + ] + } + }, + + 'bidId': '30b31c1838de1e4', + 'bidderRequestId': '22edbae2733bf67', + 'auctionId': '1d1a030790a478', + 'adUnitCode': 'testDiv3' + }, ]; @@ -163,7 +233,7 @@ describe('dspxAdapter', function () { expect(request1.method).to.equal('GET'); expect(request1.url).to.equal(ENDPOINT_URL); let data = request1.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); - expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&bcat=IAB2%2CIAB4&dvt=desktop&did_netid=123&did_uid2=456&auctionId=1d1a030790a475&pbcode=testDiv1&media_types%5Bbanner%5D=300x250'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&bcat=IAB2%2CIAB4&dvt=desktop&did_netid=123&did_id5=ID5-ZHMOcvSShIBZiIth_yYh9odjNFxVEmMQ_i5TArPfWw!ID5*dtrjfV5mPLasyya5TW2IE9oVzQZwx7xRPGyAYS4hcWkAAOoxoFef4bIoREpQys8x&did_id5_linktype=2&did_uid2=456&did_sharedid=01EXPPGZ9C8NKG1MTXVHV98505&did_pubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61&did_cpubcid=e09ab6a3-ae74-4f01-b2e8-81b141d6dc61&schain%5Bver%5D=1.0&schain%5Bcomplete%5D=1&schain%5Bnodes%5D%5B0%5D%5Basi%5D=example.com&schain%5Bnodes%5D%5B0%5D%5Bsid%5D=0&schain%5Bnodes%5D%5B0%5D%5Bhp%5D=1&schain%5Bnodes%5D%5B0%5D%5Brid%5D=bidrequestid&schain%5Bnodes%5D%5B0%5D%5Bdomain%5D=example.com&auctionId=1d1a030790a475&pbcode=testDiv1&media_types%5Bbanner%5D=300x250'); }); var request2 = spec.buildRequests([bidRequests[1]], bidderRequest)[0]; @@ -193,14 +263,61 @@ describe('dspxAdapter', function () { expect(request4.method).to.equal('GET'); expect(request4.url).to.equal(ENDPOINT_URL_DEV); let data = request4.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); - expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&pbver=test&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv3&media_types%5Bvideo%5D=640x480&media_types%5Bbanner%5D=300x250'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&pbver=test&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv3&media_types%5Bvideo%5D=640x480&media_types%5Bbanner%5D=300x250&vctx=instream&vpl%5Bprotocols%5D%5B0%5D=1&vpl%5Bprotocols%5D%5B1%5D=2&vpl%5Bplaybackmethod%5D%5B0%5D=2&vpl%5Bskip%5D=1'); }); var request5 = spec.buildRequests([bidRequests[4]], bidderRequestWithoutGdpr)[0]; it('sends bid video request to our endpoint via GET', function () { expect(request5.method).to.equal('GET'); let data = request5.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); - expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=101&srw=640&srh=480&idt=100&bid_id=30b31c1838de1e41&pbver=test&vf=vast4&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv4&media_types%5Bvideo%5D=640x480'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=101&srw=640&srh=480&idt=100&bid_id=30b31c1838de1e41&pbver=test&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv4&media_types%5Bvideo%5D=640x480&vctx=instream&vf=vast4&vpl%5Bprotocols%5D%5B0%5D=1&vpl%5Bprotocols%5D%5B1%5D=2&vpl%5Bplaybackmethod%5D%5B0%5D=2&vpl%5Bskip%5D=1'); + }); + + var request6 = spec.buildRequests([bidRequests[5]], bidderRequestWithoutGdpr)[0]; + it('sends bid request without gdprConsent to our DEV endpoint with overriden DEV params via GET', function () { + expect(request6.method).to.equal('GET'); + expect(request6.url).to.equal('http://localhost'); + let data = request6.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&'); + expect(data).to.equal('_f=auto&alternative=prebid_js&inventory_item_id=107&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&pbver=test&pfilter%5Btest%5D=1&prebidDevMode=1&auctionId=1d1a030790a478&pbcode=testDiv3&media_types%5Bvideo%5D=640x480&media_types%5Bbanner%5D=300x250&vctx=instream&vpl%5Bmimes%5D%5B0%5D=video%2Fmp4&vpl%5Bprotocols%5D%5B0%5D=1&vpl%5Bprotocols%5D%5B1%5D=2&vpl%5Bplaybackmethod%5D%5B0%5D=2&vpl%5Bskip%5D=1'); + }); + + // bidfloor tests + const getFloorResponse = {currency: 'EUR', floor: 5}; + let testBidRequest = deepClone(bidRequests[1]); + let floorRequest = spec.buildRequests([testBidRequest], bidderRequestWithoutGdpr)[0]; + + // 1. getBidFloor not exist AND bidfloor not exist - no floorprice in request + it('bidfloor is not exists in request', function () { + expect(floorRequest.data).to.not.contain('floorprice'); + }); + + // 2. getBidFloor not exist AND pfilter.floorprice exist - use pfilter.floorprice property + it('bidfloor is equal 0.5', function () { + testBidRequest = deepClone(bidRequests[0]); + testBidRequest.params.pfilter = { + 'floorprice': 0.5 + }; + floorRequest = spec.buildRequests([testBidRequest], bidderRequestWithoutGdpr)[0]; + expect(floorRequest.data).to.contain('floorprice%5D=0.5'); + }); + + // 3. getBidFloor exist AND pfilter.floorprice not exist - use getFloor method + it('bidfloor is equal 5', function () { + testBidRequest = deepClone(bidRequests[1]); + testBidRequest.getFloor = () => getFloorResponse; + floorRequest = spec.buildRequests([testBidRequest], bidderRequestWithoutGdpr)[0]; + expect(floorRequest.data).to.contain('floorprice%5D=5'); + }); + + // 4. getBidFloor exist AND pfilter.floorprice exist -> use getFloor method + it('bidfloor is equal 0.35', function () { + testBidRequest = deepClone(bidRequests[0]); + testBidRequest.getFloor = () => getFloorResponse; + testBidRequest.params.pfilter = { + 'floorprice': 0.35 + }; + floorRequest = spec.buildRequests([testBidRequest], bidderRequestWithoutGdpr)[0]; + expect(floorRequest.data).to.contain('floorprice%5D=0.35'); }); }); @@ -212,7 +329,7 @@ describe('dspxAdapter', function () { 'width': '300', 'height': '250', 'type': 'sspHTML', - 'tag': '', + 'adTag': '', 'requestId': '220ed41385952a', 'currency': 'EUR', 'ttl': 60, @@ -233,7 +350,25 @@ describe('dspxAdapter', function () { 'currency': 'EUR', 'ttl': 60, 'netRevenue': true, - 'zone': '6682' + 'zone': '6682', + 'renderer': {id: 1, url: '//player.example.com', options: {}} + } + }; + let serverVideoResponseVastUrl = { + 'body': { + 'cpm': 5000000, + 'crid': 100500, + 'width': '300', + 'height': '250', + 'requestId': '220ed41385952a', + 'type': 'vast2', + 'currency': 'EUR', + 'ttl': 60, + 'netRevenue': true, + 'zone': '6682', + 'vastUrl': 'https://local/vasturl1', + 'videoCacheKey': 'cache_123', + 'bid_appendix': {'someField': 'someValue'} } }; @@ -246,10 +381,10 @@ describe('dspxAdapter', function () { dealId: '', currency: 'EUR', netRevenue: true, - ttl: 300, + ttl: 60, type: 'sspHTML', ad: '', - meta: {advertiserDomains: ['bdomain']} + meta: {advertiserDomains: ['bdomain']}, }, { requestId: '23beaa6af6cdde', cpm: 0.5, @@ -263,7 +398,24 @@ describe('dspxAdapter', function () { type: 'vast2', vastXml: '{"reason":7001,"status":"accepted"}', mediaType: 'video', - meta: {advertiserDomains: []} + meta: {advertiserDomains: []}, + renderer: {} + }, { + requestId: '23beaa6af6cdde', + cpm: 0.5, + width: 0, + height: 0, + creativeId: 100500, + dealId: '', + currency: 'EUR', + netRevenue: true, + ttl: 60, + type: 'vast2', + vastUrl: 'https://local/vasturl1', + videoCacheKey: 'cache_123', + mediaType: 'video', + meta: {advertiserDomains: []}, + someField: 'someValue' }]; it('should get the correct bid response by display ad', function () { @@ -287,7 +439,7 @@ describe('dspxAdapter', function () { 'mediaTypes': { 'video': { 'playerSize': [640, 480], - 'context': 'instream' + 'context': 'outstream' } }, 'data': { @@ -299,6 +451,25 @@ describe('dspxAdapter', function () { expect(result[0].meta.advertiserDomains.length).to.equal(0); }); + it('should get the correct dspx video bid response by display ad (vastUrl)', function () { + let bidRequest = [{ + 'method': 'GET', + 'url': ENDPOINT_URL, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream' + } + }, + 'data': { + 'bid_id': '30b31c1838de1e' + } + }]; + let result = spec.interpretResponse(serverVideoResponseVastUrl, bidRequest[0]); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[2])); + expect(result[0].meta.advertiserDomains.length).to.equal(0); + }); + it('handles empty bid response', function () { let response = { body: {}