diff --git a/adapters.json b/adapters.json index fa5e1d228d6..5edf8f107d0 100644 --- a/adapters.json +++ b/adapters.json @@ -69,7 +69,8 @@ }, { "rubicon": { - "alias": "rubiconLite" + "alias": "rubiconLite", + "supportedMediaTypes": ["video"] } }, { diff --git a/src/adapters/rubicon.js b/src/adapters/rubicon.js index 8baccc2dd87..838d8928dfa 100644 --- a/src/adapters/rubicon.js +++ b/src/adapters/rubicon.js @@ -7,6 +7,17 @@ import { STATUS } from 'src/constants'; const RUBICON_BIDDER_CODE = 'rubicon'; +// use deferred function call since version isn't defined yet at this point +function getIntegration() { + return 'pbjs_lite_' + $$PREBID_GLOBAL$$.version; +} + +// use protocol relative urls for http or https +const FASTLANE_ENDPOINT = '//fastlane.rubiconproject.com/a/api/fastlane.json'; +const VIDEO_ENDPOINT = '//optimized-by-adv.rubiconproject.com/v1/auction/video'; + +const TIMEOUT_BUFFER = 500; + var sizeMap = { 1:'468x60', 2:'728x90', @@ -49,7 +60,12 @@ function RubiconAdapter() { bids.forEach(bid => { try { - ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true}); + // Video endpoint only accepts POST calls + if (bid.mediaType === 'video') { + ajax(VIDEO_ENDPOINT, bidCallback, buildVideoRequestPayload(bid, bidderRequest), {withCredentials: true}); + } else { + ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true}); + } } catch(err) { utils.logError('Error sending rubicon request for placement code ' + bid.placementCode, null, err); addErrorBid(); @@ -77,6 +93,82 @@ function RubiconAdapter() { }); } + function _getScreenResolution() { + return [window.screen.width, window.screen.height].join('x'); + } + + function buildVideoRequestPayload(bid, bidderRequest) { + bid.startTime = new Date().getTime(); + + let params = bid.params; + + if(!params || typeof params.video !== 'object') { + throw 'Invalid Video Bid'; + } + + let size; + if(params.video.playerWidth && params.video.playerHeight) { + size = [ + params.video.playerWidth, + params.video.playerHeight + ]; + } else if( + Array.isArray(bid.sizes) && bid.sizes.length > 0 && + Array.isArray(bid.sizes[0]) && bid.sizes[0].length > 1 + ) { + size = bid.sizes[0]; + } else { + throw "Invalid Video Bid - No size provided"; + } + + let postData = { + page_url: !params.referrer ? utils.getTopWindowUrl() : params.referrer, + resolution: _getScreenResolution(), + account_id: params.accountId, + integration: getIntegration(), + timeout: bidderRequest.timeout - (Date.now() - bidderRequest.auctionStart + TIMEOUT_BUFFER), + stash_creatives: true, + ae_pass_through_parameters: params.video.aeParams, + slots: [] + }; + + // Define the slot object + let slotData = { + site_id: params.siteId, + zone_id: params.zoneId, + position: params.position || 'btf', + floor: 0.01, + element_id: bid.placementCode, + name: bid.placementCode, + language: params.video.language, + width: size[0], + height: size[1] + }; + + // check and add inventory, keywords, visitor and size_id data + if(params.video.size_id) { + slotData.size_id = params.video.size_id; + } else { + throw "Invalid Video Bid - Invalid Ad Type!"; + } + + if(params.inventory && typeof params.inventory === 'object') { + slotData.inventory = params.inventory; + } + + if(params.keywords && Array.isArray(params.keywords)) { + slotData.keywords = params.keywords; + } + + if(params.visitor && typeof params.visitor === 'object') { + slotData.visitor = params.visitor; + } + + postData.slots.push(slotData); + + return(JSON.stringify(postData)); + } + function buildOptimizedCall(bid) { bid.startTime = new Date().getTime(); @@ -113,8 +205,8 @@ function RubiconAdapter() { 'alt_size_ids', parsedSizes.slice(1).join(',') || undefined, 'p_pos', position, 'rp_floor', '0.01', - 'tk_flint', 'pbjs.lite', - 'p_screen_res', window.screen.width +'x'+ window.screen.height, + 'tk_flint', getIntegration(), + 'p_screen_res', _getScreenResolution(), 'kw', keywords, 'tk_user_key', userId ]; @@ -136,7 +228,7 @@ function RubiconAdapter() { (memo, curr, index) => index % 2 === 0 && queryString[index + 1] !== undefined ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, - '//fastlane.rubiconproject.com/a/api/fastlane.json?' // use protocol relative link for http or https + FASTLANE_ENDPOINT + '?' ).slice(0, -1); // remove trailing & } @@ -151,23 +243,29 @@ function RubiconAdapter() { `; function handleRpCB(responseText, bidRequest) { - let responseObj = JSON.parse(responseText); // can throw + var responseObj = JSON.parse(responseText), // can throw + ads = responseObj.ads, + adResponseKey = bidRequest.placementCode; - if( - typeof responseObj !== 'object' || - responseObj.status !== 'ok' || - !Array.isArray(responseObj.ads) || - responseObj.ads.length < 1 - ) { + // check overall response + if(typeof responseObj !== 'object' || responseObj.status !== 'ok') { throw 'bad response'; } - var ads = responseObj.ads; + // video ads array is wrapped in an object + if (bidRequest.mediaType === 'video' && typeof ads === 'object') { + ads = ads[adResponseKey]; + } + + // check the ad response + if(!Array.isArray(ads) || ads.length < 1) { + throw 'invalid ad response'; + } // if there are multiple ads, sort by CPM ads = ads.sort(_adCpmSort); - ads.forEach(function (ad) { + ads.forEach(ad => { if(ad.status !== 'ok') { throw 'bad ad status'; } @@ -178,9 +276,18 @@ function RubiconAdapter() { bid.creative_id = ad.ad_id; bid.bidderCode = bidRequest.bidder; bid.cpm = ad.cpm || 0; - bid.ad = _renderCreative(ad.script, ad.impression_id); - [bid.width, bid.height] = sizeMap[ad.size_id].split('x').map(num => Number(num)); bid.dealId = ad.deal; + if (bidRequest.mediaType === 'video') { + bid.width = bidRequest.params.video.playerWidth; + bid.height = bidRequest.params.video.playerHeight; + bid.vastUrl = ad.creative_depot_url; + bid.descriptionUrl = ad.impression_id; + bid.impression_id = ad.impression_id; + } else { + bid.ad = _renderCreative(ad.script, ad.impression_id); + [bid.width, bid.height] = sizeMap[ad.size_id].split('x').map(num => Number(num)); + } + try { bidmanager.addBidResponse(bidRequest.placementCode, bid); diff --git a/src/adserver.js b/src/adserver.js index fce4695363f..b4ec8a22a63 100644 --- a/src/adserver.js +++ b/src/adserver.js @@ -32,7 +32,7 @@ exports.dfpAdserver = function (options, urlComponents) { var bid = adserver.getWinningBidByCode(); this.urlComponents.search.description_url = encodeURIComponent(bid.descriptionUrl); this.urlComponents.search.cust_params = getCustomParams(bid.adserverTargeting); - this.urlComponents.correlator = Date.now(); + this.urlComponents.search.correlator = Date.now(); }; adserver.verifyAdserverTag = function() { diff --git a/test/spec/adapters/rubicon_spec.js b/test/spec/adapters/rubicon_spec.js index ff3a7050249..a875def399f 100644 --- a/test/spec/adapters/rubicon_spec.js +++ b/test/spec/adapters/rubicon_spec.js @@ -7,18 +7,38 @@ import {parse as parseQuery} from 'querystring'; var CONSTANTS = require('src/constants.json'); +const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid + describe('the rubicon adapter', () => { let sandbox, adUnit, bidderRequest; + function createVideoBidderRequest() { + let bid = bidderRequest.bids[0]; + bid.mediaType = 'video'; + bid.params.video = { + 'language': 'en', + 'p_aso.video.ext.skip': true, + 'p_aso.video.ext.skipdelay': 15, + 'playerHeight': 320, + 'playerWidth': 640, + 'size_id': 201, + 'aeParams': { + 'p_aso.video.ext.skip': '1', + 'p_aso.video.ext.skipdelay': '15' + } + }; + } + beforeEach(() => { sandbox = sinon.sandbox.create(); adUnit = { code: '/19968336/header-bid-tag-0', sizes: [[300, 250], [320, 50]], + mediaType: 'video', bids: [ { bidder: 'rubicon', @@ -75,6 +95,7 @@ describe('the rubicon adapter', () => { } ], start: 1472239426002, + auctionStart: 1472239426000, timeout: 5000 }; @@ -93,7 +114,7 @@ describe('the rubicon adapter', () => { sandbox.stub(rubiconAdapter, 'callBids'); adapterManager.callBids({ - adUnits: [clone(adUnit)] + adUnits: [clone(adUnit)] }); let bidderRequest = rubiconAdapter.callBids.getCall(0).args[0]; @@ -105,6 +126,9 @@ describe('the rubicon adapter', () => { expect(bidderRequest).to.have.deep.property('bids[0]') .to.have.property('bidder', 'rubicon'); + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('mediaType', 'video'); + expect(bidderRequest).to.have.deep.property('bids[0]') .to.have.property('placementCode', adUnit.code); @@ -148,7 +172,7 @@ describe('the rubicon adapter', () => { ordering = masSizeOrdering([[120, 600], [320, 50], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); expect(ordering).to.deep.equal([2, 9, 8, 16, 43, 65, 126]); - }) + }); }); @@ -156,7 +180,7 @@ describe('the rubicon adapter', () => { let rubiconAdapter; - describe('requests', () => { + describe('for requests', () => { let xhr, bids; @@ -177,84 +201,160 @@ describe('the rubicon adapter', () => { xhr.restore(); }); - it('should make a well-formed optimized request', () => { - - rubiconAdapter.callBids(bidderRequest); - - let request = xhr.requests[0]; - - let [path, query] = request.url.split('?'); - query = parseQuery(query); - - expect(path).to.equal( - '//fastlane.rubiconproject.com/a/api/fastlane.json' - ); - - let expectedQuery = { - 'account_id': '14062', - 'site_id': '70608', - 'zone_id': '335918', - 'size_id': '15', - 'alt_size_ids': '43', - 'p_pos': 'atf', - 'rp_floor': '0.01', - 'tk_flint': 'pbjs.lite', - 'p_screen_res': /\d+x\d+/, - 'tk_user_key': '12346', - 'kw': 'a,b,c', - 'tg_v.ucat': 'new', - 'tg_v.lastsearch': 'iphone', - 'tg_i.rating': '5-star', - 'tg_i.prodtype': 'tech', - 'rf': 'localhost' - }; - - // test that all values above are both present and correct - Object.keys(expectedQuery).forEach(key => { - let value = expectedQuery[key]; - if(value instanceof RegExp) { - expect(query[key]).to.match(value); - } else { - expect(query[key]).to.equal(value); - } + describe("to fastlane", () => { + + it('should make a well-formed request', () => { + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let [path, query] = request.url.split('?'); + query = parseQuery(query); + + expect(path).to.equal( + '//fastlane.rubiconproject.com/a/api/fastlane.json' + ); + + let expectedQuery = { + 'account_id': '14062', + 'site_id': '70608', + 'zone_id': '335918', + 'size_id': '15', + 'alt_size_ids': '43', + 'p_pos': 'atf', + 'rp_floor': '0.01', + 'tk_flint': INTEGRATION, + 'p_screen_res': /\d+x\d+/, + 'tk_user_key': '12346', + 'kw': 'a,b,c', + 'tg_v.ucat': 'new', + 'tg_v.lastsearch': 'iphone', + 'tg_i.rating': '5-star', + 'tg_i.prodtype': 'tech', + 'rf': 'localhost' + }; + + // test that all values above are both present and correct + Object.keys(expectedQuery).forEach(key => { + let value = expectedQuery[key]; + if(value instanceof RegExp) { + expect(query[key]).to.match(value); + } else { + expect(query[key]).to.equal(value); + } + }); + + expect(query).to.have.property('rand'); + }); - expect(query).to.have.property('rand'); + it('should use rubicon sizes if present', () => { - }); + var sizesBidderRequest = clone(bidderRequest); + sizesBidderRequest.bids[0].params.sizes = [55, 57, 59]; + + rubiconAdapter.callBids(sizesBidderRequest); - it('should use rubicon sizes if present', () => { + let query = parseQuery(xhr.requests[0].url.split('?')[1]); - var sizesBidderRequest = clone(bidderRequest); - sizesBidderRequest.bids[0].params.sizes = [55, 57, 59]; + expect(query['size_id']).to.equal('55'); + expect(query['alt_size_ids']).to.equal('57,59'); + + }); - rubiconAdapter.callBids(sizesBidderRequest); + it('should not send a request and register an error bid if no valid sizes', () => { - let query = parseQuery(xhr.requests[0].url.split('?')[1]); + var sizesBidderRequest = clone(bidderRequest); + sizesBidderRequest.bids[0].sizes = [[620,250],[300,251]]; - expect(query['size_id']).to.equal('55'); - expect(query['alt_size_ids']).to.equal('57,59'); + rubiconAdapter.callBids(sizesBidderRequest); + + expect(xhr.requests.length).to.equal(0); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + + }); }); - it('should not send a request and register an error bid if no valid sizes', () => { + describe('for video requests', () => { - var sizesBidderRequest = clone(bidderRequest); - sizesBidderRequest.bids[0].sizes = [[620,250],[300,251]]; + beforeEach(() => { + createVideoBidderRequest(); - rubiconAdapter.callBids(sizesBidderRequest); + sandbox.stub(Date, "now", () => + bidderRequest.auctionStart + 100 + ); + }); + + it('should make a well-formed video request', () => { + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let url = request.url; + let post = JSON.parse(request.requestBody); + + expect(url).to.equal('//optimized-by-adv.rubiconproject.com/v1/auction/video'); + + expect(post).to.have.property('page_url').that.is.a('string'); + expect(post.resolution).to.match(/\d+x\d+/); + expect(post.account_id).to.equal('14062'); + expect(post.integration).to.equal(INTEGRATION); + expect(post).to.have.property('timeout').that.is.a('number'); + expect(post.timeout < 5000).to.equal(true); + expect(post.stash_creatives).to.equal(true); + + expect(post).to.have.property('ae_pass_through_parameters'); + expect(post.ae_pass_through_parameters) + .to.have.property('p_aso.video.ext.skip') + .that.equals('1'); + expect(post.ae_pass_through_parameters) + .to.have.property('p_aso.video.ext.skipdelay') + .that.equals('15'); + + expect(post).to.have.property('slots') + .with.length.of(1); - expect(xhr.requests.length).to.equal(0); + let slot = post.slots[0]; - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(slot.site_id).to.equal('70608'); + expect(slot.zone_id).to.equal('335918'); + expect(slot.position).to.equal('atf'); + expect(slot.floor).to.equal(.01); + expect(slot.element_id).to.equal(bidderRequest.bids[0].placementCode); + expect(slot.name).to.equal(bidderRequest.bids[0].placementCode); + expect(slot.language).to.equal('en'); + expect(slot.width).to.equal(640); + expect(slot.height).to.equal(320); + expect(slot.size_id).to.equal(201); + + expect(slot).to.have.property('inventory').that.is.an('object'); + expect(slot.inventory).to.have.property('rating').that.equals('5-star'); + expect(slot.inventory).to.have.property('prodtype').that.equals('tech'); + + expect(slot).to.have.property('keywords') + .that.is.an('array') + .of.length(3) + .that.deep.equals(['a', 'b', 'c']); + + expect(slot).to.have.property('visitor').that.is.an('object'); + expect(slot.visitor).to.have.property('ucat').that.equals('new'); + expect(slot.visitor).to.have.property('lastsearch').that.equals('iphone'); + + }); }); }); + + describe('response handler', () => { let bids, server, @@ -278,217 +378,278 @@ describe('the rubicon adapter', () => { server.restore(); }); - it('should handle a success response and sort by cpm', () => { - - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [ - { - "status": "ok", - "impression_id": "153dc240-8229-4604-b8f5-256933b9374c", - "size_id": "15", - "ad_id": "6", - "advertiser": 7, - "network": 8, - "creative_id": 9, - "type": "script", - "script": "alert('foo')", - "campaign_id": 10, - "cpm": 0.811, - "targeting": [ + describe('for fastlane', () => { + + it('should handle a success response and sort by cpm', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [ + { + "status": "ok", + "impression_id": "153dc240-8229-4604-b8f5-256933b9374c", + "size_id": "15", + "ad_id": "6", + "advertiser": 7, + "network": 8, + "creative_id": 9, + "type": "script", + "script": "alert('foo')", + "campaign_id": 10, + "cpm": 0.811, + "targeting": [ + { + "key": "rpfl_14062", + "values": [ + "15_tier_all_test" + ] + } + ] + }, + { + "status": "ok", + "impression_id": "153dc240-8229-4604-b8f5-256933b9374d", + "size_id": "43", + "ad_id": "7", + "advertiser": 7, + "network": 8, + "creative_id": 9, + "type": "script", + "script": "alert('foo')", + "campaign_id": 10, + "cpm": 0.911, + "targeting": [ + { + "key": "rpfl_14062", + "values": [ + "15_tier_all_test" + ] + } + ] + } + ] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledTwice).to.equal(true); + + expect(bids).to.be.lengthOf(2); + + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal("rubicon"); + expect(bids[0].width).to.equal(320); + expect(bids[0].height).to.equal(50); + expect(bids[0].cpm).to.equal(0.911); + expect(bids[0].ad).to.contain(`alert('foo')`) + .and.to.contain(``) + .and.to.contain(`
`); + + expect(bids[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[1].bidderCode).to.equal("rubicon"); + expect(bids[1].width).to.equal(300); + expect(bids[1].height).to.equal(250); + expect(bids[1].cpm).to.equal(0.811); + expect(bids[1].ad).to.contain(`alert('foo')`) + .and.to.contain(``) + .and.to.contain(`
`); + }); + + it('should be fine with a CPM of 0', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "ok", + "cpm": 0, + "size_id": 15 + }] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + }); + + it('should handle an error with no ads returned', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should handle an error with bad status', () => { + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "not_ok", + }] + })); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should handle an error because of malformed json response', () => { + server.respondWith("{test{"); + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + }); + + it('should not register an error bid when a success call to addBidResponse throws an error', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "account_id": 14062, + "site_id": 70608, + "zone_id": 530022, + "size_id": 15, + "alt_size_ids": [ + 43 + ], + "tracking": "", + "inventory": {}, + "ads": [{ + "status": "ok", + "cpm": .8, + "size_id": 15 + }] + })); + + addBidResponseAction = function() { + throw new Error("test error"); + }; + + rubiconAdapter.callBids(bidderRequest); + + server.respond(); + + // was calling twice for same bid, but should only call once + expect(bidManager.addBidResponse.calledOnce).to.equal(true); + expect(bids).to.be.lengthOf(1); + + }); + + }); + + describe('for video', () => { + + beforeEach(() => { + createVideoBidderRequest(); + }); + + it('should register a successful bid', () => { + + server.respondWith(JSON.stringify({ + "status": "ok", + "ads": { + "/19968336/header-bid-tag-0": [ { - "key": "rpfl_14062", - "values": [ - "15_tier_all_test" - ] + "status": "ok", + "cpm": 1, + "tier": "tier0200", + "targeting": { + "rpfl_8000": "201_tier0200", + "rpfl_elemid": "/19968336/header-bid-tag-0" + }, + "impression_id": "a40fe16e-d08d-46a9-869d-2e1573599e0c", + "site_id": 88888, + "zone_id": 54321, + "creative_type": "video", + "creative_depot_url": "https://optimized-by-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml", + "ad_id": 999999, + "size_id": 201, + "advertiser": 12345 } ] }, - { - "status": "ok", - "impression_id": "153dc240-8229-4604-b8f5-256933b9374d", - "size_id": "43", - "ad_id": "7", - "advertiser": 7, - "network": 8, - "creative_id": 9, - "type": "script", - "script": "alert('foo')", - "campaign_id": 10, - "cpm": 0.911, - "targeting": [ - { - "key": "rpfl_14062", - "values": [ - "15_tier_all_test" - ] - } - ] - } - ] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledTwice).to.equal(true); - - expect(bids).to.be.lengthOf(2); - - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[0].bidderCode).to.equal("rubicon"); - expect(bids[0].width).to.equal(320); - expect(bids[0].height).to.equal(50); - expect(bids[0].cpm).to.equal(0.911); - expect(bids[0].ad).to.contain(`alert('foo')`) - .and.to.contain(``) - .and.to.contain(`
`); - - expect(bids[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[1].bidderCode).to.equal("rubicon"); - expect(bids[1].width).to.equal(300); - expect(bids[1].height).to.equal(250); - expect(bids[1].cpm).to.equal(0.811); - expect(bids[1].ad).to.contain(`alert('foo')`) - .and.to.contain(``) - .and.to.contain(`
`); - }); + "account_id": 7780 + })); - it('should be fine with a CPM of 0', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "ok", - "cpm": 0, - "size_id": 15 - }] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - }); - - it('should handle an error with no ads returned', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); - - it('should handle an error with bad status', () => { - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "not_ok", - }] - })); - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); + rubiconAdapter.callBids(bidderRequest); - it('should handle an error because of malformed json response', () => { - server.respondWith("{test{"); + server.respond(); - rubiconAdapter.callBids(bidderRequest); + // was calling twice for same bid, but should only call once + expect(bidManager.addBidResponse.calledOnce).to.equal(true); - server.respond(); + expect(bids).to.be.lengthOf(1); - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal('rubicon'); + expect(bids[0].creative_id).to.equal(999999); + expect(bids[0].cpm).to.equal(1); + expect(bids[0].descriptionUrl).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); + expect(bids[0].vastUrl).to.equal( + 'https://optimized-by-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml' + ); + expect(bids[0].impression_id).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); - it('should not register an error bid when a success call to addBidResponse throws an error', () => { - - server.respondWith(JSON.stringify({ - "status": "ok", - "account_id": 14062, - "site_id": 70608, - "zone_id": 530022, - "size_id": 15, - "alt_size_ids": [ - 43 - ], - "tracking": "", - "inventory": {}, - "ads": [{ - "status": "ok", - "cpm": .8, - "size_id": 15 - }] - })); - - addBidResponseAction = function() { - throw new Error("test error"); - }; - - rubiconAdapter.callBids(bidderRequest); - - server.respond(); - - // was calling twice for same bid, but should only call once - expect(bidManager.addBidResponse.calledOnce).to.equal(true); - expect(bids).to.be.lengthOf(1); + }); }); - }) + }); });