diff --git a/libraries/nexx360Utils/index.js b/libraries/nexx360Utils/index.js new file mode 100644 index 000000000000..5952c077fcd8 --- /dev/null +++ b/libraries/nexx360Utils/index.js @@ -0,0 +1,155 @@ +import { deepAccess, deepSetValue, logInfo } from '../../src/utils.js'; +import {Renderer} from '../../src/Renderer.js'; +import { getCurrencyFromBidderRequest } from '../ortb2Utils/currency.js'; +import { INSTREAM, OUTSTREAM } from '../../src/video.js'; +import { BANNER, NATIVE } from '../../src/mediaTypes.js'; + +const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +/** + * Register the user sync pixels which should be dropped after the auction. + * + /** + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse + * @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions + * @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync + * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests + * + */ + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + */ +export function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { + if (typeof serverResponses === 'object' && + serverResponses != null && + serverResponses.length > 0 && + serverResponses[0].hasOwnProperty('body') && + serverResponses[0].body.hasOwnProperty('ext') && + serverResponses[0].body.ext.hasOwnProperty('cookies') && + typeof serverResponses[0].body.ext.cookies === 'object') { + return serverResponses[0].body.ext.cookies.slice(0, 5); + } else { + return []; + } +}; + +function outstreamRender(response) { + response.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [response.width, response.height], + targetId: response.divId, + adResponse: response.vastXml, + rendererOptions: { + showBigPlayButton: false, + showProgressBar: 'bar', + showVolume: false, + allowFullscreen: true, + skippable: false, + content: response.vastXml + } + }); + }); +}; + +export function createRenderer(bid, url) { + const renderer = Renderer.install({ + id: bid.id, + url: url, + loaded: false, + adUnitCode: bid.ext.adUnitCode, + targetId: bid.ext.divId, + }); + renderer.setRender(outstreamRender); + return renderer; +}; + +export function enrichImp(imp, bidRequest) { + deepSetValue(imp, 'tagid', bidRequest.adUnitCode); + deepSetValue(imp, 'ext.adUnitCode', bidRequest.adUnitCode); + const divId = bidRequest.params.divId || bidRequest.adUnitCode; + deepSetValue(imp, 'ext.divId', divId); + if (imp.video) { + const playerSize = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + const videoContext = deepAccess(bidRequest, 'mediaTypes.video.context'); + deepSetValue(imp, 'video.ext.playerSize', playerSize); + deepSetValue(imp, 'video.ext.context', videoContext); + } + return imp; +} + +export function enrichRequest(request, amxId, bidderRequest, pageViewId, bidderVersion) { + if (amxId) { + deepSetValue(request, 'ext.localStorage.amxId', amxId); + if (!request.user) request.user = {}; + if (!request.user.ext) request.user.ext = {}; + if (!request.user.ext.eids) request.user.ext.eids = []; + request.user.ext.eids.push({ + source: 'amxdt.net', + uids: [{ + id: `${amxId}`, + atype: 1 + }] + }); + } + deepSetValue(request, 'ext.version', '$prebid.version$'); + deepSetValue(request, 'ext.source', 'prebid.js'); + deepSetValue(request, 'ext.pageViewId', pageViewId); + deepSetValue(request, 'ext.bidderVersion', bidderVersion); + deepSetValue(request, 'cur', [getCurrencyFromBidderRequest(bidderRequest) || 'USD']); + if (!request.user) request.user = {}; + return request; +}; + +export function createResponse(bid, respBody) { + const response = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + creativeId: bid.crid, + currency: respBody.cur, + netRevenue: true, + ttl: 120, + mediaType: [OUTSTREAM, INSTREAM].includes(bid.ext.mediaType) ? 'video' : bid.ext.mediaType, + meta: { + advertiserDomains: bid.adomain, + demandSource: bid.ext.ssp, + }, + }; + if (bid.dealid) response.dealid = bid.dealid; + + if (bid.ext.mediaType === BANNER) response.ad = bid.adm; + if ([INSTREAM, OUTSTREAM].includes(bid.ext.mediaType)) response.vastXml = bid.adm; + + if (bid.ext.mediaType === OUTSTREAM) { + response.renderer = createRenderer(bid, OUTSTREAM_RENDERER_URL); + if (bid.ext.divId) response.divId = bid.ext.divId + }; + + if (bid.ext.mediaType === NATIVE) { + try { + response.native = { ortb: JSON.parse(bid.adm) } + } catch (e) {} + } + return response; +} + +/** + * Get the AMX ID + * @return { string | false } false if localstorageNotEnabled + */ +export function getAmxId(storage, bidderCode) { + if (!storage.localStorageIsEnabled()) { + logInfo(`localstorage not enabled for ${bidderCode}`); + return false; + } + const amxId = storage.getDataFromLocalStorage('__amuidpb'); + return amxId || false; +} diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index 0214d33c1219..ff5dc8daaa42 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -1,12 +1,11 @@ -import { deepAccess, deepSetValue, generateUUID, logError, logInfo } from '../src/utils.js'; -import {Renderer} from '../src/Renderer.js'; +import { deepSetValue, generateUUID, logError, logInfo } from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js' -import { INSTREAM, OUTSTREAM } from '../src/video.js'; -import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js'; + +import { createResponse, enrichImp, enrichRequest, getAmxId, getUserSyncs } from '../libraries/nexx360Utils/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -17,12 +16,10 @@ import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.j * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests */ -const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; - const BIDDER_CODE = 'nexx360'; const REQUEST_URL = 'https://fast.nexx360.io/booster'; const PAGE_VIEW_ID = generateUUID(); -const BIDDER_VERSION = '5.0'; +const BIDDER_VERSION = '6.0'; const GVLID = 965; const NEXXID_KEY = 'nexx360_storage'; @@ -41,7 +38,7 @@ const ALIASES = [ { code: 'scoremedia', gvlid: 965 } ]; -export const storage = getStorageManager({ +export const STORAGE = getStorageManager({ bidderCode: BIDDER_CODE, }); @@ -52,14 +49,14 @@ export const storage = getStorageManager({ */ export function getNexx360LocalStorage() { - if (!storage.localStorageIsEnabled()) { + if (!STORAGE.localStorageIsEnabled()) { logInfo(`localstorage not enabled for Nexx360`); return false; } - const output = storage.getDataFromLocalStorage(NEXXID_KEY); + const output = STORAGE.getDataFromLocalStorage(NEXXID_KEY); if (output === null) { const nexx360Storage = { nexx360Id: generateUUID() }; - storage.setDataInLocalStorage(NEXXID_KEY, JSON.stringify(nexx360Storage)); + STORAGE.setDataInLocalStorage(NEXXID_KEY, JSON.stringify(nexx360Storage)); return nexx360Storage; } try { @@ -69,32 +66,15 @@ export function getNexx360LocalStorage() { } } -/** - * Get the AMX ID - * @return { string | false } false if localstorageNotEnabled - */ -export function getAmxId() { - if (!storage.localStorageIsEnabled()) { - logInfo(`localstorage not enabled for Nexx360`); - return false; - } - const amxId = storage.getDataFromLocalStorage('__amuidpb'); - return amxId || false; -} - const converter = ortbConverter({ context: { netRevenue: true, // or false if your adapter should set bidResponse.netRevenue = false ttl: 90, // default bidResponse.ttl (when not specified in ORTB response.seatbid[].bid[].exp) }, imp(buildImp, bidRequest, context) { - const imp = buildImp(bidRequest, context); - deepSetValue(imp, 'tagid', bidRequest.adUnitCode); - deepSetValue(imp, 'ext.adUnitCode', bidRequest.adUnitCode); - if (bidRequest.params.adUnitPath) deepSetValue(imp, 'ext.adUnitPath', bidRequest.params.adUnitPath); - if (bidRequest.params.adUnitName) deepSetValue(imp, 'ext.adUnitName', bidRequest.params.adUnitName); + let imp = buildImp(bidRequest, context); + imp = enrichImp(imp, bidRequest); const divId = bidRequest.params.divId || bidRequest.adUnitCode; - deepSetValue(imp, 'ext.divId', divId); const slotEl = document.getElementById(divId); if (slotEl) { deepSetValue(imp, 'ext.dimensions.slotW', slotEl.offsetWidth); @@ -105,41 +85,15 @@ const converter = ortbConverter({ if (bidRequest.params.tagId) deepSetValue(imp, 'ext.nexx360.tagId', bidRequest.params.tagId); if (bidRequest.params.placement) deepSetValue(imp, 'ext.nexx360.placement', bidRequest.params.placement); if (bidRequest.params.videoTagId) deepSetValue(imp, 'ext.nexx360.videoTagId', bidRequest.params.videoTagId); + if (bidRequest.params.adUnitPath) deepSetValue(imp, 'ext.adUnitPath', bidRequest.params.adUnitPath); + if (bidRequest.params.adUnitName) deepSetValue(imp, 'ext.adUnitName', bidRequest.params.adUnitName); if (bidRequest.params.allBids) deepSetValue(imp, 'ext.nexx360.allBids', bidRequest.params.allBids); - if (imp.video) { - const playerSize = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); - const videoContext = deepAccess(bidRequest, 'mediaTypes.video.context'); - deepSetValue(imp, 'video.ext.playerSize', playerSize); - deepSetValue(imp, 'video.ext.context', videoContext); - } return imp; }, request(buildRequest, imps, bidderRequest, context) { - const request = buildRequest(imps, bidderRequest, context); - const nexx360LocalStorage = getNexx360LocalStorage(); - if (nexx360LocalStorage) { - deepSetValue(request, 'ext.localStorage.nexx360Id', nexx360LocalStorage.nexx360Id); - } - const amxId = getAmxId(); - if (amxId) deepSetValue(request, 'ext.localStorage.amxId', amxId); - deepSetValue(request, 'ext.version', '$prebid.version$'); - deepSetValue(request, 'ext.source', 'prebid.js'); - deepSetValue(request, 'ext.pageViewId', PAGE_VIEW_ID); - deepSetValue(request, 'ext.bidderVersion', BIDDER_VERSION); - deepSetValue(request, 'cur', [getCurrencyFromBidderRequest(bidderRequest) || 'USD']); - if (!request.user) request.user = {}; - if (getAmxId()) { - if (!request.user.ext) request.user.ext = {}; - if (!request.user.ext.eids) request.user.ext.eids = []; - request.user.ext.eids.push({ - source: 'amxdt.net', - uids: [{ - id: `${getAmxId()}`, - atype: 1 - }] - }); - } - + let request = buildRequest(imps, bidderRequest, context); + const amxId = getAmxId(STORAGE, BIDDER_CODE); + request = enrichRequest(request, amxId, bidderRequest, PAGE_VIEW_ID, BIDDER_VERSION); return request; }, }); @@ -205,106 +159,19 @@ function interpretResponse(serverResponse) { const { bidderSettings } = getGlobal(); const allowAlternateBidderCodes = bidderSettings && bidderSettings.standard ? bidderSettings.standard.allowAlternateBidderCodes : false; - let responses = []; + const responses = []; for (let i = 0; i < respBody.seatbid.length; i++) { const seatbid = respBody.seatbid[i]; for (let j = 0; j < seatbid.bid.length; j++) { const bid = seatbid.bid[j]; - const response = { - requestId: bid.impid, - cpm: bid.price, - width: bid.w, - height: bid.h, - creativeId: bid.crid, - currency: respBody.cur, - netRevenue: true, - ttl: 120, - mediaType: [OUTSTREAM, INSTREAM].includes(bid.ext.mediaType) ? 'video' : bid.ext.mediaType, - meta: { - advertiserDomains: bid.adomain, - demandSource: bid.ext.ssp, - }, - }; - if (bid.dealid) response.dealid = bid.dealid; + const response = createResponse(bid, respBody); if (allowAlternateBidderCodes) response.bidderCode = `n360_${bid.ext.ssp}`; - - if (bid.ext.mediaType === BANNER) { - if (bid.adm) { - response.ad = bid.adm; - } else { - response.adUrl = bid.ext.adUrl; - } - } - if ([INSTREAM, OUTSTREAM].includes(bid.ext.mediaType)) response.vastXml = bid.adm; - - if (bid.ext.mediaType === OUTSTREAM) { - response.renderer = createRenderer(bid, OUTSTREAM_RENDERER_URL); - if (bid.ext.divId) response.divId = bid.ext.divId - }; - if (bid.ext.mediaType === NATIVE) { - try { - response.native = { - ortb: JSON.parse(bid.adm) - } - } catch (e) {} - } responses.push(response); } } return responses; } -/** - * Register the user sync pixels which should be dropped after the auction. - * - * @param {SyncOptions} syncOptions Which user syncs are allowed? - * @param {ServerResponse[]} serverResponses List of server's responses. - * @return {UserSync[]} The user syncs which should be dropped. - */ -function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { - if (typeof serverResponses === 'object' && - serverResponses != null && - serverResponses.length > 0 && - serverResponses[0].hasOwnProperty('body') && - serverResponses[0].body.hasOwnProperty('ext') && - serverResponses[0].body.ext.hasOwnProperty('cookies') && - typeof serverResponses[0].body.ext.cookies === 'object') { - return serverResponses[0].body.ext.cookies.slice(0, 5); - } else { - return []; - } -}; - -function outstreamRender(response) { - response.renderer.push(() => { - window.ANOutstreamVideo.renderAd({ - sizes: [response.width, response.height], - targetId: response.divId, - adResponse: response.vastXml, - rendererOptions: { - showBigPlayButton: false, - showProgressBar: 'bar', - showVolume: false, - allowFullscreen: true, - skippable: false, - content: response.vastXml - } - }); - }); -} - -function createRenderer(bid, url) { - const renderer = Renderer.install({ - id: bid.id, - url: url, - loaded: false, - adUnitCode: bid.ext.adUnitCode, - targetId: bid.ext.divId, - }); - renderer.setRender(outstreamRender); - return renderer; -} - export const spec = { code: BIDDER_CODE, gvlid: GVLID, diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js index b8bed5f01def..237ffd4c8ce6 100644 --- a/test/spec/modules/nexx360BidAdapter_spec.js +++ b/test/spec/modules/nexx360BidAdapter_spec.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { - spec, storage, getNexx360LocalStorage, + spec, STORAGE, getNexx360LocalStorage, } from 'modules/nexx360BidAdapter.js'; import { sandbox } from 'sinon'; -import { getAmxId } from '../../../modules/nexx360BidAdapter'; +import { getAmxId } from '../../../libraries/nexx360Utils'; describe('Nexx360 bid adapter tests', () => { const DEFAULT_OPTIONS = { @@ -91,7 +91,7 @@ describe('Nexx360 bid adapter tests', () => { describe('getNexx360LocalStorage disabled', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => false); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => false); }); it('We test if we get the nexx360Id', () => { const output = getNexx360LocalStorage(); @@ -104,9 +104,9 @@ describe('Nexx360 bid adapter tests', () => { describe('getNexx360LocalStorage enabled but nothing', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => null); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => null); }); it('We test if we get the nexx360Id', () => { const output = getNexx360LocalStorage(); @@ -119,9 +119,9 @@ describe('Nexx360 bid adapter tests', () => { describe('getNexx360LocalStorage enabled but wrong payload', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => '{"nexx360Id":"5ad89a6e-7801-48e7-97bb-fe6f251f6cb4",}'); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => '{"nexx360Id":"5ad89a6e-7801-48e7-97bb-fe6f251f6cb4",}'); }); it('We test if we get the nexx360Id', () => { const output = getNexx360LocalStorage(); @@ -134,9 +134,9 @@ describe('Nexx360 bid adapter tests', () => { describe('getNexx360LocalStorage enabled', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => '{"nexx360Id":"5ad89a6e-7801-48e7-97bb-fe6f251f6cb4"}'); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => '{"nexx360Id":"5ad89a6e-7801-48e7-97bb-fe6f251f6cb4"}'); }); it('We test if we get the nexx360Id', () => { const output = getNexx360LocalStorage(); @@ -149,12 +149,12 @@ describe('Nexx360 bid adapter tests', () => { describe('getAmxId() with localStorage enabled and data not set', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => null); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => null); }); it('We test if we get the amxId', () => { - const output = getAmxId(); + const output = getAmxId(STORAGE, 'nexx360'); expect(output).to.be.eql(false); }); after(() => { @@ -164,12 +164,12 @@ describe('Nexx360 bid adapter tests', () => { describe('getAmxId() with localStorage enabled and data set', () => { before(() => { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => 'abcdef'); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => 'abcdef'); }); it('We test if we get the amxId', () => { - const output = getAmxId(); + const output = getAmxId(STORAGE, 'nexx360'); expect(output).to.be.eql('abcdef'); }); after(() => { @@ -188,6 +188,9 @@ describe('Nexx360 bid adapter tests', () => { maxHeight: '350px', } }); + sandbox.stub(STORAGE, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(STORAGE, 'setDataInLocalStorage'); + sandbox.stub(STORAGE, 'getDataFromLocalStorage').callsFake((key) => 'abcdef'); }); describe('We test with a multiple display bids', () => { const sampleBids = [ @@ -210,32 +213,6 @@ describe('Nexx360 bid adapter tests', () => { bidId: '44a2706ac3574', bidderRequestId: '359bf8a3c06b2e', auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', - userIdAsEids: [ - { - source: 'id5-sync.com', - uids: [ - { - id: 'ID5*xe3R0Pbrc5Y4WBrb5UZSWTiS1t9DU2LgQrhdZOgFdXMoglhqmjs_SfBbyHfSYGZKKIT4Gf-XOQ_anA3iqi0hJSiFyD3aICGHDJFxNS8LO84ohwTQ0EiwOexZAbBlH0chKIhbvdGBfuouNuVF_YHCoyiLQJDp3WQiH96lE9MH2T0ojRqoyR623gxAWlBCBPh7KI4bYtZlet3Vtr-gH5_xqCiSEd7aYV37wHxUTSN38Isok_0qDCHg4pKXCcVM2h6FKJSGmvw-xPm9HkfkIcbh1CiVVG4nREP142XrBecdzhQomNlcalmwdzGHsuHPjTP-KJraa15yvvZDceq-f_YfECicDllYBLEsg24oPRM-ibMonWtT9qOm5dSfWS5G_r09KJ4HMB6REICq1wleDD1mwSigXkM_nxIKa4TxRaRqEekoooWRwuKA5-euHN3xxNfIKKP19EtGhuNTs0YdCSe8_w', - atype: 1, - ext: { - linkType: 2 - } - } - ] - }, - { - source: 'domain.com', - uids: [ - { - id: 'value read from cookie or local storage', - atype: 1, - ext: { - stype: 'ppuid' - } - } - ] - } - ], }, { bidder: 'nexx360', @@ -256,7 +233,7 @@ describe('Nexx360 bid adapter tests', () => { bidderRequestId: '359bf8a3c06b2e', auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', } - ] + ]; const bidderRequest = { bidderCode: 'nexx360', auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', @@ -357,12 +334,27 @@ describe('Nexx360 bid adapter tests', () => { version: requestContent.ext.version, source: 'prebid.js', pageViewId: requestContent.ext.pageViewId, - bidderVersion: '5.0', + bidderVersion: '6.0', + localStorage: { amxId: 'abcdef'} }, cur: [ 'USD', ], - user: {}, + user: { + ext: { + eids: [ + { + source: 'amxdt.net', + uids: [ + { + id: 'abcdef', + atype: 1, + } + ] + } + ] + } + }, }; expect(requestContent).to.be.eql(expectedRequest); }); @@ -434,64 +426,6 @@ describe('Nexx360 bid adapter tests', () => { const output = spec.interpretResponse(response); expect(output.length).to.be.eql(0); }); - it('banner responses with adUrl only', () => { - const response = { - body: { - id: 'a8d3a675-a4ba-4d26-807f-c8f2fad821e0', - cur: 'USD', - seatbid: [ - { - bid: [ - { - id: '4427551302944024629', - impid: '226175918ebeda', - price: 1.5, - adomain: [ - 'http://prebid.org', - ], - crid: '98493581', - ssp: 'appnexus', - h: 600, - w: 300, - dealid: 'testdeal', - cat: [ - 'IAB3-1', - ], - ext: { - adUnitCode: 'div-1', - mediaType: 'banner', - adUrl: 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493', - ssp: 'appnexus', - }, - }, - ], - seat: 'appnexus', - }, - ], - ext: { - id: 'de3de7c7-e1cf-4712-80a9-94eb26bfc718', - cookies: [], - }, - }, - }; - - const output = spec.interpretResponse(response); - const expectedOutput = [{ - requestId: '226175918ebeda', - cpm: 1.5, - width: 300, - height: 600, - creativeId: '98493581', - currency: 'USD', - netRevenue: true, - dealid: 'testdeal', - ttl: 120, - mediaType: 'banner', - meta: { advertiserDomains: ['http://prebid.org'], demandSource: 'appnexus' }, - adUrl: 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493', - }]; - expect(output).to.eql(expectedOutput); - }); it('banner responses with adm', () => { const response = { body: {