UNPKG

mk9-prebid

Version:

Header Bidding Management Library

1,353 lines (1,207 loc) 50 kB
import { expect } from 'chai'; import { spec } from 'modules/appnexusBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import * as bidderFactory from 'src/adapters/bidderFactory.js'; import { auctionManager } from 'src/auctionManager.js'; import { deepClone } from 'src/utils.js'; import { config } from 'src/config.js'; const ENDPOINT = 'https://ib.adnxs.com/ut/v3/prebid'; describe('AppNexusAdapter', function () { const adapter = newBidder(spec); describe('inherited functions', function () { it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); }); describe('isBidRequestValid', function () { let bid = { 'bidder': 'appnexus', 'params': { 'placementId': '10433394' }, 'adUnitCode': 'adunit-code', 'sizes': [[300, 250], [300, 600]], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', }; 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 () { let bid = Object.assign({}, bid); delete bid.params; bid.params = { 'member': '1234', 'invCode': 'ABCD' }; expect(spec.isBidRequestValid(bid)).to.equal(true); }); it('should return false when required params are not passed', function () { let bid = Object.assign({}, bid); delete bid.params; bid.params = { 'placementId': 0 }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); describe('buildRequests', function () { let getAdUnitsStub; let bidRequests = [ { 'bidder': 'appnexus', 'params': { 'placementId': '10433394' }, 'adUnitCode': 'adunit-code', 'sizes': [[300, 250], [300, 600]], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843' } ]; beforeEach(function() { getAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits').callsFake(function() { return []; }); }); afterEach(function() { getAdUnitsStub.restore(); }); it('should parse out private sizes', function () { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', privateSizes: [300, 250] } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].private_sizes).to.exist; expect(payload.tags[0].private_sizes).to.deep.equal([{width: 300, height: 250}]); }); it('should add publisher_id in request', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', publisherId: '1231234' } }); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].publisher_id).to.exist; expect(payload.tags[0].publisher_id).to.deep.equal(1231234); expect(payload.publisher_id).to.exist; expect(payload.publisher_id).to.deep.equal(1231234); }) it('should add source and verison to the tag', function () { const request = spec.buildRequests(bidRequests); const payload = JSON.parse(request.data); expect(payload.sdk).to.exist; expect(payload.sdk).to.deep.equal({ source: 'pbjs', version: '$prebid.version$' }); }); it('should populate the ad_types array on all requests', function () { let adUnits = [{ code: 'adunit-code', mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } }, bids: [{ bidder: 'appnexus', params: { placementId: '10433394' } }], transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' }]; ['banner', 'video', 'native'].forEach(type => { getAdUnitsStub.callsFake(function(...args) { return adUnits; }); const bidRequest = Object.assign({}, bidRequests[0]); bidRequest.mediaTypes = {}; bidRequest.mediaTypes[type] = {}; const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].ad_types).to.deep.equal([type]); if (type === 'banner') { delete adUnits[0].mediaTypes; } }); }); it('should not populate the ad_types array when adUnit.mediaTypes is undefined', function() { const bidRequest = Object.assign({}, bidRequests[0]); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].ad_types).to.not.exist; }); it('should populate the ad_types array on outstream requests', function () { const bidRequest = Object.assign({}, bidRequests[0]); bidRequest.mediaTypes = {}; bidRequest.mediaTypes.video = {context: 'outstream'}; const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].ad_types).to.deep.equal(['video']); expect(payload.tags[0].hb_source).to.deep.equal(1); }); it('sends bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(bidRequests); expect(request.url).to.equal(ENDPOINT); expect(request.method).to.equal('POST'); }); it('should attach valid video params to the tag', function () { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', video: { id: 123, minduration: 100, foobar: 'invalid' } } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].video).to.deep.equal({ id: 123, minduration: 100 }); expect(payload.tags[0].hb_source).to.deep.equal(1); }); it('should include ORTB video values when video params were not set', function() { let bidRequest = deepClone(bidRequests[0]); bidRequest.params = { placementId: '1234235', video: { skippable: true, playback_method: ['auto_play_sound_off', 'auto_play_sound_unknown'], context: 'outstream' } }; bidRequest.mediaTypes = { video: { playerSize: [640, 480], context: 'outstream', mimes: ['video/mp4'], skip: 0, minduration: 5, api: [1, 5, 6], playbackmethod: [2, 4] } }; const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].video).to.deep.equal({ minduration: 5, playback_method: 2, skippable: true, context: 4 }); expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4]) }); it('should add video property when adUnit includes a renderer', function () { const videoData = { mediaTypes: { video: { context: 'outstream', mimes: ['video/mp4'] } }, params: { placementId: '10433394', video: { skippable: true, playback_method: ['auto_play_sound_off'] } } }; let bidRequest1 = deepClone(bidRequests[0]); bidRequest1 = Object.assign({}, bidRequest1, videoData, { renderer: { url: 'https://test.renderer.url', render: function () {} } }); let bidRequest2 = deepClone(bidRequests[0]); bidRequest2.adUnitCode = 'adUnit_code_2'; bidRequest2 = Object.assign({}, bidRequest2, videoData); const request = spec.buildRequests([bidRequest1, bidRequest2]); const payload = JSON.parse(request.data); expect(payload.tags[0].video).to.deep.equal({ skippable: true, playback_method: 2, custom_renderer_present: true }); expect(payload.tags[1].video).to.deep.equal({ skippable: true, playback_method: 2 }); }); it('should attach valid user params to the tag', function () { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', user: { externalUid: '123', segments: [123, { id: 987, value: 876 }], foobar: 'invalid' } } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.user).to.exist; expect(payload.user).to.deep.equal({ external_uid: '123', segments: [{id: 123}, {id: 987, value: 876}] }); }); it('should attach reserve param when either bid param or getFloor function exists', function () { let getFloorResponse = { currency: 'USD', floor: 3 }; let request, payload = null; let bidRequest = deepClone(bidRequests[0]); // 1 -> reserve not defined, getFloor not defined > empty request = spec.buildRequests([bidRequest]); payload = JSON.parse(request.data); expect(payload.tags[0].reserve).to.not.exist; // 2 -> reserve is defined, getFloor not defined > reserve is used bidRequest.params = { 'placementId': '10433394', 'reserve': 0.5 }; request = spec.buildRequests([bidRequest]); payload = JSON.parse(request.data); expect(payload.tags[0].reserve).to.exist.and.to.equal(0.5); // 3 -> reserve is defined, getFloor is defined > getFloor is used bidRequest.getFloor = () => getFloorResponse; request = spec.buildRequests([bidRequest]); payload = JSON.parse(request.data); expect(payload.tags[0].reserve).to.exist.and.to.equal(3); }); it('should duplicate adpod placements into batches and set correct maxduration', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 300, durationRangeSec: [15, 30], } } } ); const request = spec.buildRequests([bidRequest]); const payload1 = JSON.parse(request[0].data); const payload2 = JSON.parse(request[1].data); // 300 / 15 = 20 total expect(payload1.tags.length).to.equal(15); expect(payload2.tags.length).to.equal(5); expect(payload1.tags[0]).to.deep.equal(payload1.tags[1]); expect(payload1.tags[0].video.maxduration).to.equal(30); expect(payload2.tags[0]).to.deep.equal(payload1.tags[1]); expect(payload2.tags[0].video.maxduration).to.equal(30); }); it('should round down adpod placements when numbers are uneven', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 123, durationRangeSec: [45], } } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags.length).to.equal(2); }); it('should duplicate adpod placements when requireExactDuration is set', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 300, durationRangeSec: [15, 30], requireExactDuration: true, } } } ); // 20 total placements with 15 max impressions = 2 requests const request = spec.buildRequests([bidRequest]); expect(request.length).to.equal(2); // 20 spread over 2 requests = 15 in first request, 5 in second const payload1 = JSON.parse(request[0].data); const payload2 = JSON.parse(request[1].data); expect(payload1.tags.length).to.equal(15); expect(payload2.tags.length).to.equal(5); // 10 placements should have max/min at 15 // 10 placemenst should have max/min at 30 const payload1tagsWith15 = payload1.tags.filter(tag => tag.video.maxduration === 15); const payload1tagsWith30 = payload1.tags.filter(tag => tag.video.maxduration === 30); expect(payload1tagsWith15.length).to.equal(10); expect(payload1tagsWith30.length).to.equal(5); // 5 placemenst with min/max at 30 were in the first request // so 5 remaining should be in the second const payload2tagsWith30 = payload2.tags.filter(tag => tag.video.maxduration === 30); expect(payload2tagsWith30.length).to.equal(5); }); it('should set durations for placements when requireExactDuration is set and numbers are uneven', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 105, durationRangeSec: [15, 30, 60], requireExactDuration: true, } } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags.length).to.equal(7); const tagsWith15 = payload.tags.filter(tag => tag.video.maxduration === 15); const tagsWith30 = payload.tags.filter(tag => tag.video.maxduration === 30); const tagsWith60 = payload.tags.filter(tag => tag.video.maxduration === 60); expect(tagsWith15.length).to.equal(3); expect(tagsWith30.length).to.equal(3); expect(tagsWith60.length).to.equal(1); }); it('should break adpod request into batches', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 225, durationRangeSec: [5], } } } ); const request = spec.buildRequests([bidRequest]); const payload1 = JSON.parse(request[0].data); const payload2 = JSON.parse(request[1].data); const payload3 = JSON.parse(request[2].data); expect(payload1.tags.length).to.equal(15); expect(payload2.tags.length).to.equal(15); expect(payload3.tags.length).to.equal(15); }); it('should contain hb_source value for adpod', function() { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '14542875' } }, { mediaTypes: { video: { context: 'adpod', playerSize: [640, 480], adPodDurationSec: 300, durationRangeSec: [15, 30], } } } ); const request = spec.buildRequests([bidRequest])[0]; const payload = JSON.parse(request.data); expect(payload.tags[0].hb_source).to.deep.equal(7); }); it('should contain hb_source value for other media', function() { let bidRequest = Object.assign({}, bidRequests[0], { mediaType: 'banner', params: { sizes: [[300, 250], [300, 600]], placementId: 13144370 } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].hb_source).to.deep.equal(1); }); it('adds brand_category_exclusion to request when set', function() { let bidRequest = Object.assign({}, bidRequests[0]); sinon .stub(config, 'getConfig') .withArgs('adpod.brandCategoryExclusion') .returns(true); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.brand_category_uniqueness).to.equal(true); config.getConfig.restore(); }); it('should attach native params to the request', function () { let bidRequest = Object.assign({}, bidRequests[0], { mediaType: 'native', nativeParams: { title: {required: true}, body: {required: true}, body2: {required: true}, image: {required: true, sizes: [100, 100]}, icon: {required: true}, cta: {required: false}, rating: {required: true}, sponsoredBy: {required: true}, privacyLink: {required: true}, displayUrl: {required: true}, address: {required: true}, downloads: {required: true}, likes: {required: true}, phone: {required: true}, price: {required: true}, salePrice: {required: true} } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].native.layouts[0]).to.deep.equal({ title: {required: true}, description: {required: true}, desc2: {required: true}, main_image: {required: true, sizes: [{ width: 100, height: 100 }]}, icon: {required: true}, ctatext: {required: false}, rating: {required: true}, sponsored_by: {required: true}, privacy_link: {required: true}, displayurl: {required: true}, address: {required: true}, downloads: {required: true}, likes: {required: true}, phone: {required: true}, price: {required: true}, saleprice: {required: true}, privacy_supported: true }); expect(payload.tags[0].hb_source).to.equal(1); }); it('should always populated tags[].sizes with 1,1 for native if otherwise not defined', function () { let bidRequest = Object.assign({}, bidRequests[0], { mediaType: 'native', nativeParams: { image: { required: true } } } ); bidRequest.sizes = [[150, 100], [300, 250]]; let request = spec.buildRequests([bidRequest]); let payload = JSON.parse(request.data); expect(payload.tags[0].sizes).to.deep.equal([{width: 150, height: 100}, {width: 300, height: 250}]); delete bidRequest.sizes; request = spec.buildRequests([bidRequest]); payload = JSON.parse(request.data); expect(payload.tags[0].sizes).to.deep.equal([{width: 1, height: 1}]); }); it('should convert keyword params to proper form and attaches to request', function () { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', keywords: { single: 'val', singleArr: ['val'], singleArrNum: [5], multiValMixed: ['value1', 2, 'value3'], singleValNum: 123, emptyStr: '', emptyArr: [''], badValue: {'foo': 'bar'} // should be dropped } } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].keywords).to.deep.equal([{ 'key': 'single', 'value': ['val'] }, { 'key': 'singleArr', 'value': ['val'] }, { 'key': 'singleArrNum', 'value': ['5'] }, { 'key': 'multiValMixed', 'value': ['value1', '2', 'value3'] }, { 'key': 'singleValNum', 'value': ['123'] }, { 'key': 'emptyStr' }, { 'key': 'emptyArr' }]); }); it('should add payment rules to the request', function () { let bidRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', usePaymentRule: true } } ); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].use_pmt_rule).to.equal(true); }); it('should add gpid to the request', function () { let testGpid = '/12345/my-gpt-tag-0'; let bidRequest = deepClone(bidRequests[0]); bidRequest.ortb2Imp = { ext: { data: { pbadslot: testGpid } } }; const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.tags[0].gpid).to.exist.and.equal(testGpid) }); it('should add gdpr consent information to the request', function () { let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; let bidderRequest = { 'bidderCode': 'appnexus', 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, 'gdprConsent': { consentString: consentString, gdprApplies: true, addtlConsent: '1~7.12.35.62.66.70.89.93.108' } }; bidderRequest.bids = bidRequests; const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.options).to.deep.equal({withCredentials: true}); const payload = JSON.parse(request.data); expect(payload.gdpr_consent).to.exist; expect(payload.gdpr_consent.consent_string).to.exist.and.to.equal(consentString); expect(payload.gdpr_consent.consent_required).to.exist.and.to.be.true; expect(payload.gdpr_consent.addtl_consent).to.exist.and.to.deep.equal([7, 12, 35, 62, 66, 70, 89, 93, 108]); }); it('should add us privacy string to payload', function() { let consentString = '1YA-'; let bidderRequest = { 'bidderCode': 'appnexus', 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, 'uspConsent': consentString }; bidderRequest.bids = bidRequests; const request = spec.buildRequests(bidRequests, bidderRequest); const payload = JSON.parse(request.data); expect(payload.us_privacy).to.exist; expect(payload.us_privacy).to.exist.and.to.equal(consentString); }); it('supports sending hybrid mobile app parameters', function () { let appRequest = Object.assign({}, bidRequests[0], { params: { placementId: '10433394', app: { id: 'B1O2W3M4AN.com.prebid.webview', geo: { lat: 40.0964439, lng: -75.3009142 }, device_id: { idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', // Apple advertising identifier aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', // Android advertising identifier md5udid: '5756ae9022b2ea1e47d84fead75220c8', // MD5 hash of the ANDROID_ID sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', // SHA1 hash of the ANDROID_ID windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' // Windows advertising identifier } } } } ); const request = spec.buildRequests([appRequest]); const payload = JSON.parse(request.data); expect(payload.app).to.exist; expect(payload.app).to.deep.equal({ appid: 'B1O2W3M4AN.com.prebid.webview' }); expect(payload.device.device_id).to.exist; expect(payload.device.device_id).to.deep.equal({ aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', md5udid: '5756ae9022b2ea1e47d84fead75220c8', sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' }); expect(payload.device.geo).to.exist; expect(payload.device.geo).to.deep.equal({ lat: 40.0964439, lng: -75.3009142 }); }); it('should add referer info to payload', function () { const bidRequest = Object.assign({}, bidRequests[0]) const bidderRequest = { refererInfo: { referer: 'https://example.com/page.html', reachedTop: true, numIframes: 2, stack: [ 'https://example.com/page.html', 'https://example.com/iframe1.html', 'https://example.com/iframe2.html' ] } } const request = spec.buildRequests([bidRequest], bidderRequest); const payload = JSON.parse(request.data); expect(payload.referrer_detection).to.exist; expect(payload.referrer_detection).to.deep.equal({ rd_ref: 'https%3A%2F%2Fexample.com%2Fpage.html', rd_top: true, rd_ifs: 2, rd_stk: bidderRequest.refererInfo.stack.map((url) => encodeURIComponent(url)).join(',') }); }); it('should populate schain if available', function () { const bidRequest = Object.assign({}, bidRequests[0], { schain: { ver: '1.0', complete: 1, nodes: [ { 'asi': 'blob.com', 'sid': '001', 'hp': 1 } ] } }); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.schain).to.deep.equal({ ver: '1.0', complete: 1, nodes: [ { 'asi': 'blob.com', 'sid': '001', 'hp': 1 } ] }); }); it('should populate coppa if set in config', function () { let bidRequest = Object.assign({}, bidRequests[0]); sinon.stub(config, 'getConfig') .withArgs('coppa') .returns(true); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.user.coppa).to.equal(true); config.getConfig.restore(); }); it('should set the X-Is-Test customHeader if test flag is enabled', function () { let bidRequest = Object.assign({}, bidRequests[0]); sinon.stub(config, 'getConfig') .withArgs('apn_test') .returns(true); const request = spec.buildRequests([bidRequest]); expect(request.options.customHeaders).to.deep.equal({'X-Is-Test': 1}); config.getConfig.restore(); }); it('should always set withCredentials: true on the request.options', function () { let bidRequest = Object.assign({}, bidRequests[0]); const request = spec.buildRequests([bidRequest]); expect(request.options.withCredentials).to.equal(true); }); it('should set simple domain variant if purpose 1 consent is not given', function () { let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; let bidderRequest = { 'bidderCode': 'appnexus', 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, 'gdprConsent': { consentString: consentString, gdprApplies: true, apiVersion: 2, vendorData: { purpose: { consents: { 1: false } } } } }; bidderRequest.bids = bidRequests; const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.url).to.equal('https://ib.adnxs-simple.com/ut/v3/prebid'); }); it('should populate eids when supported userIds are available', function () { const bidRequest = Object.assign({}, bidRequests[0], { userId: { tdid: 'sample-userid', uid2: { id: 'sample-uid2-value' }, criteoId: 'sample-criteo-userid', netId: 'sample-netId-userid', idl_env: 'sample-idl-userid', flocId: { id: 'sample-flocid-value', version: 'chrome.1.0' } } }); const request = spec.buildRequests([bidRequest]); const payload = JSON.parse(request.data); expect(payload.eids).to.deep.include({ source: 'adserver.org', id: 'sample-userid', rti_partner: 'TDID' }); expect(payload.eids).to.deep.include({ source: 'criteo.com', id: 'sample-criteo-userid', }); expect(payload.eids).to.deep.include({ source: 'chrome.com', id: 'sample-flocid-value' }); expect(payload.eids).to.deep.include({ source: 'netid.de', id: 'sample-netId-userid', }); expect(payload.eids).to.deep.include({ source: 'liveramp.com', id: 'sample-idl-userid' }); expect(payload.eids).to.deep.include({ source: 'uidapi.com', id: 'sample-uid2-value', rti_partner: 'UID2' }); }); it('should populate iab_support object at the root level if omid support is detected', function () { // with bid.params.frameworks let bidRequest_A = Object.assign({}, bidRequests[0], { params: { frameworks: [1, 2, 5, 6], video: { frameworks: [1, 2, 5, 6] } } }); let request = spec.buildRequests([bidRequest_A]); let payload = JSON.parse(request.data); expect(payload.iab_support).to.be.an('object'); expect(payload.iab_support).to.deep.equal({ omidpn: 'Appnexus', omidpv: '$prebid.version$' }); expect(payload.tags[0].banner_frameworks).to.be.an('array'); expect(payload.tags[0].banner_frameworks).to.deep.equal([1, 2, 5, 6]); expect(payload.tags[0].video_frameworks).to.be.an('array'); expect(payload.tags[0].video_frameworks).to.deep.equal([1, 2, 5, 6]); expect(payload.tags[0].video.frameworks).to.not.exist; // without bid.params.frameworks const bidRequest_B = Object.assign({}, bidRequests[0]); request = spec.buildRequests([bidRequest_B]); payload = JSON.parse(request.data); expect(payload.iab_support).to.not.exist; expect(payload.tags[0].banner_frameworks).to.not.exist; expect(payload.tags[0].video_frameworks).to.not.exist; // with video.frameworks but it is not an array const bidRequest_C = Object.assign({}, bidRequests[0], { params: { video: { frameworks: "'1', '2', '3', '6'" } } }); request = spec.buildRequests([bidRequest_C]); payload = JSON.parse(request.data); expect(payload.iab_support).to.not.exist; expect(payload.tags[0].banner_frameworks).to.not.exist; expect(payload.tags[0].video_frameworks).to.not.exist; }); }) describe('interpretResponse', function () { let bfStub; before(function() { bfStub = sinon.stub(bidderFactory, 'getIabSubCategory'); }); after(function() { bfStub.restore(); }); let response = { 'version': '3.0.0', 'tags': [ { 'uuid': '3db3773286ee59', 'tag_id': 10433394, 'auction_id': '4534722592064951574', 'nobid': false, 'no_ad_url': 'https://lax1-ib.adnxs.com/no-ad', 'timeout_ms': 10000, 'ad_profile_id': 27079, 'ads': [ { 'content_source': 'rtb', 'ad_type': 'banner', 'buyer_member_id': 958, 'creative_id': 29681110, 'media_type_id': 1, 'media_subtype_id': 1, 'cpm': 0.5, 'cpm_publisher_currency': 0.5, 'publisher_currency_code': '$', 'client_initiated_ad_counting': true, 'viewability': { 'config': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>' }, 'rtb': { 'banner': { 'content': '<!-- Creative -->', 'width': 300, 'height': 250 }, 'trackers': [ { 'impression_urls': [ 'https://lax1-ib.adnxs.com/impression' ], 'video_events': {} } ] } } ] } ] }; it('should get correct bid response', function () { let expectedResponse = [ { 'requestId': '3db3773286ee59', 'cpm': 0.5, 'creativeId': 29681110, 'dealId': undefined, 'width': 300, 'height': 250, 'ad': '<!-- Creative -->', 'mediaType': 'banner', 'currency': 'USD', 'ttl': 300, 'netRevenue': true, 'adUnitCode': 'code', 'appnexus': { 'buyerMemberId': 958 } } ]; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', adUnitCode: 'code' }] } let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); it('handles nobid responses', function () { let response = { 'version': '0.0.1', 'tags': [{ 'uuid': '84ab500420319d', 'tag_id': 5976557, 'auction_id': '297492697822162468', 'nobid': true }] }; let bidderRequest; let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result.length).to.equal(0); }); it('handles outstream video responses', function () { let response = { 'tags': [{ 'uuid': '84ab500420319d', 'ads': [{ 'ad_type': 'video', 'cpm': 0.500000, 'notify_url': 'imptracker.com', 'rtb': { 'video': { 'content': '<!-- VAST Creative -->' } }, 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>' }] }] }; let bidderRequest = { bids: [{ bidId: '84ab500420319d', adUnitCode: 'code', mediaTypes: { video: { context: 'outstream' } } }] } let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result[0]).to.have.property('vastXml'); expect(result[0]).to.have.property('vastImpUrl'); expect(result[0]).to.have.property('mediaType', 'video'); }); it('handles instream video responses', function () { let response = { 'tags': [{ 'uuid': '84ab500420319d', 'ads': [{ 'ad_type': 'video', 'cpm': 0.500000, 'notify_url': 'imptracker.com', 'rtb': { 'video': { 'asset_url': 'https://sample.vastURL.com/here/vid' } }, 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>' }] }] }; let bidderRequest = { bids: [{ bidId: '84ab500420319d', adUnitCode: 'code', mediaTypes: { video: { context: 'instream' } } }] } let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result[0]).to.have.property('vastUrl'); expect(result[0]).to.have.property('vastImpUrl'); expect(result[0]).to.have.property('mediaType', 'video'); }); it('handles adpod responses', function () { let response = { 'tags': [{ 'uuid': '84ab500420319d', 'ads': [{ 'ad_type': 'video', 'brand_category_id': 10, 'cpm': 0.500000, 'notify_url': 'imptracker.com', 'rtb': { 'video': { 'asset_url': 'https://sample.vastURL.com/here/adpod', 'duration_ms': 30000, } }, 'viewability': { 'config': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>' } }] }] }; let bidderRequest = { bids: [{ bidId: '84ab500420319d', adUnitCode: 'code', mediaTypes: { video: { context: 'adpod' } } }] }; bfStub.returns('1'); let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result[0]).to.have.property('vastUrl'); expect(result[0].video.context).to.equal('adpod'); expect(result[0].video.durationSeconds).to.equal(30); }); it('handles native responses', function () { let response1 = deepClone(response); response1.tags[0].ads[0].ad_type = 'native'; response1.tags[0].ads[0].rtb.native = { 'title': 'Native Creative', 'desc': 'Cool description great stuff', 'desc2': 'Additional body text', 'ctatext': 'Do it', 'sponsored': 'AppNexus', 'icon': { 'width': 0, 'height': 0, 'url': 'https://cdn.adnxs.com/icon.png' }, 'main_img': { 'width': 2352, 'height': 1516, 'url': 'https://cdn.adnxs.com/img.png' }, 'link': { 'url': 'https://www.appnexus.com', 'fallback_url': '', 'click_trackers': ['https://nym1-ib.adnxs.com/click'] }, 'impression_trackers': ['https://example.com'], 'rating': '5', 'displayurl': 'https://AppNexus.com/?url=display_url', 'likes': '38908320', 'downloads': '874983', 'price': '9.99', 'saleprice': 'FREE', 'phone': '1234567890', 'address': '28 W 23rd St, New York, NY 10010', 'privacy_link': 'https://appnexus.com/?url=privacy_url', 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=;css_selector=.pb-click;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>' }; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', adUnitCode: 'code' }] } let result = spec.interpretResponse({ body: response1 }, {bidderRequest}); expect(result[0].native.title).to.equal('Native Creative'); expect(result[0].native.body).to.equal('Cool description great stuff'); expect(result[0].native.cta).to.equal('Do it'); expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png'); }); it('supports configuring outstream renderers', function () { const outstreamResponse = deepClone(response); outstreamResponse.tags[0].ads[0].rtb.video = {}; outstreamResponse.tags[0].ads[0].renderer_url = 'renderer.js'; const bidderRequest = { bids: [{ bidId: '3db3773286ee59', renderer: { options: { adText: 'configured' } }, mediaTypes: { video: { context: 'outstream' } } }] }; const result = spec.interpretResponse({ body: outstreamResponse }, {bidderRequest}); expect(result[0].renderer.config).to.deep.equal( bidderRequest.bids[0].renderer.options ); }); it('should add deal_priority and deal_code', function() { let responseWithDeal = deepClone(response); responseWithDeal.tags[0].ads[0].ad_type = 'video'; responseWithDeal.tags[0].ads[0].deal_priority = 5; responseWithDeal.tags[0].ads[0].deal_code = '123'; responseWithDeal.tags[0].ads[0].rtb.video = { duration_ms: 1500, player_width: 640, player_height: 340, }; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', adUnitCode: 'code', mediaTypes: { video: { context: 'adpod' } } }] } let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest}); expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']); expect(result[0].video.dealTier).to.equal(5); }); it('should add advertiser id', function() { let responseAdvertiserId = deepClone(response); responseAdvertiserId.tags[0].ads[0].advertiser_id = '123'; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', adUnitCode: 'code' }] } let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest}); expect(Object.keys(result[0].meta)).to.include.members(['advertiserId']); }); it('should add advertiserDomains', function() { let responseAdvertiserId = deepClone(response); responseAdvertiserId.tags[0].ads[0].adomain = ['123']; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', adUnitCode: 'code' }] } let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest}); expect(Object.keys(result[0].meta)).to.include.members(['advertiserDomains']); expect(Object.keys(result[0].meta.advertiserDomains)).to.deep.equal([]); }); }); });