diff --git a/modules/gambidBidAdapter.js b/modules/gambidBidAdapter.js
new file mode 100644
index 00000000000..bde378f8d26
--- /dev/null
+++ b/modules/gambidBidAdapter.js
@@ -0,0 +1,168 @@
+import * as utils from 'src/utils';
+import { registerBidder } from 'src/adapters/bidderFactory';
+import { config } from 'src/config';
+
+function getTopFrame() {
+ try {
+ return window.top === window ? 1 : 0;
+ } catch (e) {
+ return 0;
+ }
+}
+
+function getTopWindowUrl() {
+ try {
+ return window.top.location.href;
+ } catch (e) {
+ utils.logMessage('Failed obtaining top window\'s URL: ', e);
+ try {
+ return window.location.href;
+ } catch (e) {
+ utils.logMessage('Failed obtaining current window\'s URL: ', e);
+ return '';
+ }
+ }
+}
+
+function getTopWindowDomain() {
+ const url = getTopWindowUrl();
+ const domainStart = url.indexOf('://') + '://'.length;
+ return url.substring(domainStart, url.indexOf('/', domainStart) < 0 ? url.length : url.indexOf('/', domainStart));
+}
+
+function getTopWindowReferer() {
+ try {
+ return window.top.document.referrer;
+ } catch (e) {
+ utils.logMessage('Failed obtaining top window\'s referrer: ', e);
+ try {
+ return window.document.referrer;
+ } catch (e) {
+ utils.logMessage('Failed obtaining current window\'s referrer: ', e);
+ return '';
+ }
+ }
+}
+
+export const spec = {
+ code: 'gambid',
+ aliases: [],
+ supportedMediaTypes: [ 'banner', 'video' ],
+
+ isBidRequestValid: function(bid) {
+ return !!bid.params.supplyPartnerId && typeof bid.params.supplyPartnerId === 'string' &&
+ (typeof bid.params[ 'rtbEndpoint' ] === 'undefined' || typeof bid.params[ 'rtbEndpoint' ] === 'string') &&
+ (typeof bid.params.bidfloor === 'undefined' || typeof bid.params.bidfloor === 'number') &&
+ (typeof bid.params[ 'adpos' ] === 'undefined' || typeof bid.params[ 'adpos' ] === 'number') &&
+ (typeof bid.params[ 'protocols' ] === 'undefined' || Array.isArray(bid.params[ 'protocols' ])) &&
+ (typeof bid.params.instl === 'undefined' || bid.params.instl === 0 || bid.params.instl === 1);
+ },
+
+ buildRequests: function(validBidRequests) {
+ return validBidRequests.map(bidRequest => {
+ const { adUnitCode, auctionId, mediaTypes, params, sizes, transactionId } = bidRequest;
+ const baseEndpoint = params[ 'rtbEndpoint' ] || 'https://rtb.gambid.io';
+ const rtbEndpoint = `${baseEndpoint}/r/${params.supplyPartnerId}/bidr?rformat=open_rtb&bidder=prebid&` + params.query || '';
+ const rtbBidRequest = {
+ 'id': auctionId,
+ 'site': {
+ 'domain': getTopWindowDomain(),
+ 'page': config.getConfig('pageUrl') || utils.getTopWindowUrl(),
+ 'ref': getTopWindowReferer()
+ },
+ 'device': {
+ 'ua': navigator.userAgent
+ },
+ 'imp': []
+ };
+
+ const imp = {
+ 'id': transactionId,
+ 'instl': params.instl === 1 ? 1 : 0,
+ 'tagid': adUnitCode,
+ 'bidfloor': params.bidfloor || 0,
+ 'bidfloorcur': 'USD',
+ 'secure': getTopWindowUrl().toLowerCase().startsWith('http://') ? 0 : 1
+ };
+
+ if (!mediaTypes || mediaTypes.banner) {
+ imp.banner = {
+ w: sizes.length ? sizes[ 0 ][ 0 ] : 300,
+ h: sizes.length ? sizes[ 0 ][ 1 ] : 250,
+ pos: params.pos || 0,
+ topframe: getTopFrame()
+ };
+ } else if (mediaTypes && mediaTypes.video) {
+ imp.video = {
+ w: sizes.length ? sizes[ 0 ][ 0 ] : 300,
+ h: sizes.length ? sizes[ 0 ][ 1 ] : 250,
+ protocols: params.protocols || [1, 2, 3, 4, 5, 6],
+ pos: params.pos || 0,
+ topframe: getTopFrame()
+ };
+ } else {
+ return;
+ }
+ rtbBidRequest.imp.push(imp);
+ return { method: 'POST', url: rtbEndpoint, data: rtbBidRequest, bidRequest };
+ });
+ },
+
+ interpretResponse: function(serverResponse, bidRequest) {
+ const response = serverResponse && serverResponse.body;
+ if (!response) {
+ utils.logError('empty response');
+ return [];
+ }
+
+ const bids = response.seatbid.reduce((acc, seatBid) => acc.concat(seatBid.bid), []);
+ const outBids = [];
+ bids.forEach(bid => {
+ const outBid = {
+ requestId: bidRequest.bidRequest.bidId,
+ cpm: bid.price,
+ width: bid.w,
+ height: bid.h,
+ ttl: 60 * 10,
+ creativeId: bid.crid,
+ netRevenue: true,
+ currency: bid.cur || response.cur
+ };
+ if (!bidRequest.bidRequest.mediaTypes || bidRequest.bidRequest.mediaTypes.banner) {
+ outBids.push(Object.assign({}, outBid, { ad: bid.adm }));
+ } else if ( bidRequest.bidRequest.mediaTypes && bidRequest.bidRequest.mediaTypes.video) {
+ outBids.push(Object.assign({}, outBid, { vastXml: bid.adm }));
+ }
+ });
+ return outBids;
+ },
+
+ getUserSyncs: function(syncOptions, serverResponses) {
+ const syncs = [];
+ serverResponses.forEach(resp => {
+ if (resp.body) {
+ const bidResponse = resp.body;
+ if (bidResponse.ext && Array.isArray(bidResponse.ext[ 'utrk' ])) {
+ bidResponse.ext[ 'utrk' ].forEach(pixel => syncs.push({ type: pixel.type, url: pixel.url }));
+ }
+ if (Array.isArray(bidResponse.seatbid)) {
+ bidResponse.seatbid.forEach(seatBid => {
+ if (Array.isArray(seatBid.bid)) {
+ seatBid.bid.forEach(bid => {
+ if (bid.ext && Array.isArray(bid.ext[ 'utrk' ])) {
+ bid.ext[ 'utrk' ].forEach(pixel => syncs.push({ type: pixel.type, url: pixel.url }));
+ }
+ });
+ }
+ });
+ }
+ }
+ });
+ return syncs;
+ },
+
+ onTimeout: function(data) {
+ utils.logWarn('Gambid request timed out.', data);
+ }
+};
+registerBidder(spec);
diff --git a/modules/gambidBidAdapter.md b/modules/gambidBidAdapter.md
new file mode 100644
index 00000000000..ddf1c8f7851
--- /dev/null
+++ b/modules/gambidBidAdapter.md
@@ -0,0 +1,81 @@
+# Overview
+
+```
+Module Name: Gamoshi's Gambid Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: arik@gamoshi.com
+```
+
+# Description
+
+Connects to Gamoshi's Gambid platform & exchange for bids.
+
+Gambid bid adapter supports Banner & Outstream Video. The *only* required parameter (in the `params` section) is the `supplyPartnerId` parameter.
+
+# Test Parameters
+```
+var adUnits = [
+
+ // Banner adUnit
+ {
+ code: 'banner-div',
+ sizes: [[300, 250], [300,600]],
+ bids: [{
+ bidder: 'gambid',
+ params: {
+
+ // ID of the supply partner you created in the Gambid dashboard
+ supplyPartnerId: '12345',
+
+ // OPTIONAL: if you have a whitelabel account on Gamoshi, specify it here
+ rtbEndpoint: 'https://my.custom-whitelabel-domain.io',
+
+ // OPTIONAL: custom bid floor
+ bidfloor: 0.03,
+
+ // OPTIONAL: if you know the ad position on the page, specify it here
+ // (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
+ adpos: 1,
+
+ // OPTIONAL: whether this is an interstitial placement (0 or 1)
+ // (see "instl" property in "Imp" object in the OpenRTB 2.3, section 3.2.2)
+ instl: 0
+ }
+ }]
+ },
+
+ // Video outstream adUnit
+ {
+ code: 'video-outstream',
+ sizes: [[640, 480]],
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ playerSize: [640, 480]
+ }
+ },
+ bids: [ {
+ bidder: 'gambid',
+ params: {
+
+ // ID of the supply partner you created in the Gambid dashboard
+ supplyPartnerId: '12345',
+
+ // OPTIONAL: if you have a whitelabel account on Gamoshi, specify it here
+ rtbEndpoint: 'https://my.custom-whitelabel-domain.io',
+
+ // OPTIONAL: custom bid floor
+ bidfloor: 0.03,
+
+ // OPTIONAL: if you know the ad position on the page, specify it here
+ // (this corresponds to "Ad Position" in OpenRTB 2.3, section 5.4)
+ adpos: 1,
+
+ // OPTIONAL: whether this is an interstitial placement (0 or 1)
+ // (see "instl" property in "Imp" object in the OpenRTB 2.3, section 3.2.2)
+ instl: 0
+ }
+ }]
+ }
+];
+```
diff --git a/test/spec/modules/gambidBidAdapter_spec.js b/test/spec/modules/gambidBidAdapter_spec.js
new file mode 100644
index 00000000000..e6cc77b3bad
--- /dev/null
+++ b/test/spec/modules/gambidBidAdapter_spec.js
@@ -0,0 +1,331 @@
+import { expect } from 'chai';
+import { spec } from 'modules/gambidBidAdapter';
+import { deepClone } from 'src/utils';
+
+const supplyPartnerId = '123';
+
+describe('GambidAdapter', () => {
+ describe('isBidRequestValid', () => {
+ it('should validate supply-partner ID', () => {
+ expect(spec.isBidRequestValid({ params: {} })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: 123 } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })).to.equal(true);
+ });
+ it('should validate RTB endpoint', () => {
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })).to.equal(true); // RTB endpoint has a default
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', rtbEndpoint: 123 } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', rtbEndpoint: 'https://some.url.com' } })).to.equal(true);
+ });
+ it('should validate bid floor', () => {
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })).to.equal(true); // bidfloor has a default
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', bidfloor: '123' } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', bidfloor: 0.1 } })).to.equal(true);
+ });
+ it('should validate adpos', () => {
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })).to.equal(true); // adpos has a default
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', adpos: '123' } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', adpos: 0.1 } })).to.equal(true);
+ });
+ it('should validate instl', () => {
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123' } })).to.equal(true); // adpos has a default
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: '123' } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: -1 } })).to.equal(false);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 0 } })).to.equal(true);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 1 } })).to.equal(true);
+ expect(spec.isBidRequestValid({ params: { supplyPartnerId: '123', instl: 2 } })).to.equal(false);
+ });
+ });
+ describe('buildRequests', () => {
+ const bidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ banner: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [ [ 300, 250 ], [ 300, 600 ] ],
+ 'transactionId': 'a123456789'
+ };
+
+ it('returns an array', () => {
+ let response;
+
+ response = spec.buildRequests([]);
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(0);
+
+ response = spec.buildRequests([ bidRequest ]);
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(1);
+
+ const adUnit1 = Object.assign({}, deepClone(bidRequest), { auctionId: '1', adUnitCode: 'a' });
+ const adUnit2 = Object.assign({}, deepClone(bidRequest), { auctionId: '1', adUnitCode: 'b' });
+ response = spec.buildRequests([adUnit1, adUnit2]);
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(2);
+ });
+
+ it('targets correct endpoint', () => {
+ let response;
+
+ response = spec.buildRequests([ bidRequest ])[ 0 ];
+ expect(response.method).to.equal('POST');
+ expect(response.url).to.match(new RegExp(`^https://rtb\\.gambid\\.io/r/${supplyPartnerId}/bidr\\?bidder=prebid&_cb=\\d+$`, 'g'));
+ expect(response.data.id).to.equal(bidRequest.auctionId);
+
+ const bidRequestWithEndpoint = deepClone(bidRequest);
+ bidRequestWithEndpoint.params.rtbEndpoint = 'https://rtb2.gambid.io/a12';
+ response = spec.buildRequests([ bidRequestWithEndpoint ])[ 0 ];
+ expect(response.url).to.match(new RegExp(`^https://rtb2\\.gambid\\.io/a12/r/${supplyPartnerId}/bidr\\?bidder=prebid&_cb=\\d+$`, 'g'));
+ });
+
+ it('builds request correctly', () => {
+ let response;
+ response = spec.buildRequests([ bidRequest ])[ 0 ];
+ expect(response.data.site.domain).to.match(new RegExp(`^localhost:\\d+$`));
+ expect(response.data.site.page).to.match(new RegExp(`^http://localhost:\\d+/$`));
+ expect(response.data.site.ref).to.equal('');
+ expect(response.data.imp.length).to.equal(1);
+ expect(response.data.imp[ 0 ].id).to.equal(bidRequest.transactionId);
+ expect(response.data.imp[ 0 ].instl).to.equal(0);
+ expect(response.data.imp[ 0 ].tagid).to.equal(bidRequest.adUnitCode);
+ expect(response.data.imp[ 0 ].bidfloor).to.equal(0);
+ expect(response.data.imp[ 0 ].bidfloorcur).to.equal('USD');
+
+ const bidRequestWithInstlEquals1 = deepClone(bidRequest);
+ bidRequestWithInstlEquals1.params.instl = 1;
+ response = spec.buildRequests([ bidRequestWithInstlEquals1 ])[ 0 ];
+ expect(response.data.imp[ 0 ].instl).to.equal(bidRequestWithInstlEquals1.params.instl);
+
+ const bidRequestWithInstlEquals0 = deepClone(bidRequest);
+ bidRequestWithInstlEquals0.params.instl = 1;
+ response = spec.buildRequests([ bidRequestWithInstlEquals0 ])[ 0 ];
+ expect(response.data.imp[ 0 ].instl).to.equal(bidRequestWithInstlEquals0.params.instl);
+
+ const bidRequestWithBidfloorEquals1 = deepClone(bidRequest);
+ bidRequestWithBidfloorEquals1.params.bidfloor = 1;
+ response = spec.buildRequests([ bidRequestWithBidfloorEquals1 ])[ 0 ];
+ expect(response.data.imp[ 0 ].bidfloor).to.equal(bidRequestWithBidfloorEquals1.params.bidfloor);
+ });
+
+ it('builds request banner object correctly', () => {
+ let response;
+
+ const bidRequestWithBanner = deepClone(bidRequest);
+ bidRequestWithBanner.mediaTypes = {
+ banner: {
+ sizes: [ [ 300, 250 ], [ 120, 600 ] ]
+ }
+ };
+
+ response = spec.buildRequests([ bidRequestWithBanner ])[ 0 ];
+ expect(response.data.imp[ 0 ].banner.w).to.equal(bidRequestWithBanner.mediaTypes.banner.sizes[ 0 ][ 0 ]);
+ expect(response.data.imp[ 0 ].banner.h).to.equal(bidRequestWithBanner.mediaTypes.banner.sizes[ 0 ][ 1 ]);
+ expect(response.data.imp[ 0 ].banner.pos).to.equal(0);
+ expect(response.data.imp[ 0 ].banner.topframe).to.equal(0);
+
+ const bidRequestWithPosEquals1 = deepClone(bidRequestWithBanner);
+ bidRequestWithPosEquals1.params.pos = 1;
+ response = spec.buildRequests([ bidRequestWithPosEquals1 ])[ 0 ];
+ expect(response.data.imp[ 0 ].banner.pos).to.equal(bidRequestWithPosEquals1.params.pos);
+ });
+
+ it('builds request video object correctly', () => {
+ let response;
+
+ const bidRequestWithVideo = deepClone(bidRequest);
+ bidRequestWithVideo.mediaTypes = {
+ video: {
+ sizes: [ [ 300, 250 ], [ 120, 600 ] ]
+ }
+ };
+
+ response = spec.buildRequests([ bidRequestWithVideo ])[ 0 ];
+ expect(response.data.imp[ 0 ].video.w).to.equal(bidRequestWithVideo.mediaTypes.video.sizes[ 0 ][ 0 ]);
+ expect(response.data.imp[ 0 ].video.h).to.equal(bidRequestWithVideo.mediaTypes.video.sizes[ 0 ][ 1 ]);
+ expect(response.data.imp[ 0 ].video.pos).to.equal(0);
+ expect(response.data.imp[ 0 ].video.topframe).to.equal(0);
+
+ const bidRequestWithPosEquals1 = deepClone(bidRequestWithVideo);
+ bidRequestWithPosEquals1.params.pos = 1;
+ response = spec.buildRequests([ bidRequestWithPosEquals1 ])[ 0 ];
+ expect(response.data.imp[ 0 ].video.pos).to.equal(bidRequestWithPosEquals1.params.pos);
+ });
+ });
+ describe('interpretResponse', () => {
+ const bannerBidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ banner: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [ [ 300, 250 ], [ 300, 600 ] ],
+ 'transactionId': 'a123456789',
+ 'bidId': '111'
+ };
+ const videoBidRequest = {
+ 'adUnitCode': 'adunit-code',
+ 'auctionId': '1d1a030790a475',
+ 'mediaTypes': {
+ video: {}
+ },
+ 'params': {
+ 'supplyPartnerId': supplyPartnerId
+ },
+ 'sizes': [ [ 300, 250 ], [ 300, 600 ] ],
+ 'transactionId': 'a123456789',
+ 'bidId': '111'
+ };
+ const rtbResponse = {
+ 'id': 'imp_5b05b9fde4b09084267a556f',
+ 'bidid': 'imp_5b05b9fde4b09084267a556f',
+ 'cur': 'USD',
+ 'ext': {
+ 'pixels': [
+ { 'type': 'iframe', 'url': '//p.gsh.io/user/sync/1' },
+ { 'type': 'image', 'url': '//p.gsh.io/user/sync/2' }
+ ]
+ },
+ 'seatbid': [
+ {
+ 'seat': 'seat1',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': '0',
+ 'impid': '1',
+ 'price': 2.016,
+ 'adid': '579ef31bfa788b9d2000d562',
+ 'nurl': 'https://p.gsh.io/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0&p=${AUCTION_PRICE}',
+ 'adm': '
',
+ 'adomain': [ 'aaa.com' ],
+ 'cid': '579ef268fa788b9d2000d55c',
+ 'crid': '579ef31bfa788b9d2000d562',
+ 'attr': [],
+ 'h': 600,
+ 'w': 120,
+ 'ext': {
+ 'pixels': [
+ { 'type': 'iframe', 'url': '//p.partner1.io/user/sync/1' }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ 'seat': 'seat2',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': '1',
+ 'impid': '1',
+ 'price': 3,
+ 'adid': '542jlhdfd2112jnjf3x',
+ 'nurl': 'https://p.gsh.io/pix/monitoring/win_notice/imp_5b05b9fde4b09084267a556f/im.gif?r=imp_5b05b9fde4b09084267a556f&i=1&a=579ef31bfa788b9d2000d562&b=0&p=${AUCTION_PRICE}',
+ 'adm': '
',
+ 'adomain': [ 'bbb.com' ],
+ 'cid': 'fgdlwjh2498ydjhg1',
+ 'crid': 'kjh34297ydh2133d',
+ 'attr': [],
+ 'h': 250,
+ 'w': 300,
+ 'ext': {
+ 'pixels': [
+ { 'type': 'image', 'url': '//p.partner2.io/user/sync/1' }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ };
+ it('returns an empty array on missing response', () => {
+ let response;
+
+ response = spec.interpretResponse(undefined, { bidRequest: bannerBidRequest });
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(0);
+
+ response = spec.interpretResponse({}, { bidRequest: bannerBidRequest });
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(0);
+ });
+ it('aggregates banner bids from all seat bids', () => {
+ const response = spec.interpretResponse({ body: rtbResponse }, { bidRequest: bannerBidRequest });
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(2);
+
+ const ad0 = response[ 0 ], ad1 = response[ 1 ];
+ expect(ad0.requestId).to.equal(bannerBidRequest.bidId);
+ expect(ad0.cpm).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].price);
+ expect(ad0.width).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].w);
+ expect(ad0.height).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].h);
+ expect(ad0.ttl).to.equal(60 * 10);
+ expect(ad0.creativeId).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].crid);
+ expect(ad0.netRevenue).to.equal(true);
+ expect(ad0.currency).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].cur || rtbResponse.cur || 'USD');
+ expect(ad0.ad).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].adm);
+ expect(ad0.vastXml).to.be.an('undefined');
+
+ expect(ad1.requestId).to.equal(bannerBidRequest.bidId);
+ expect(ad1.cpm).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].price);
+ expect(ad1.width).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].w);
+ expect(ad1.height).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].h);
+ expect(ad1.ttl).to.equal(60 * 10);
+ expect(ad1.creativeId).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].crid);
+ expect(ad1.netRevenue).to.equal(true);
+ expect(ad1.currency).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].cur || rtbResponse.cur || 'USD');
+ expect(ad1.ad).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].adm);
+ expect(ad1.vastXml).to.be.an('undefined');
+
+ // expect(ad1.ad).to.be.an('undefined');
+ // expect(ad1.vastXml).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].adm);
+ });
+ it('aggregates video bids from all seat bids', () => {
+ const response = spec.interpretResponse({ body: rtbResponse }, { bidRequest: videoBidRequest });
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(2);
+
+ const ad0 = response[ 0 ], ad1 = response[ 1 ];
+ expect(ad0.requestId).to.equal(videoBidRequest.bidId);
+ expect(ad0.cpm).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].price);
+ expect(ad0.width).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].w);
+ expect(ad0.height).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].h);
+ expect(ad0.ttl).to.equal(60 * 10);
+ expect(ad0.creativeId).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].crid);
+ expect(ad0.netRevenue).to.equal(true);
+ expect(ad0.currency).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].cur || rtbResponse.cur || 'USD');
+ expect(ad0.ad).to.be.an('undefined');
+ expect(ad0.vastXml).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].adm);
+
+ expect(ad1.requestId).to.equal(videoBidRequest.bidId);
+ expect(ad1.cpm).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].price);
+ expect(ad1.width).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].w);
+ expect(ad1.height).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].h);
+ expect(ad1.ttl).to.equal(60 * 10);
+ expect(ad1.creativeId).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].crid);
+ expect(ad1.netRevenue).to.equal(true);
+ expect(ad1.currency).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].cur || rtbResponse.cur || 'USD');
+ expect(ad1.ad).to.be.an('undefined');
+ expect(ad1.vastXml).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].adm);
+ });
+ it('aggregates user-sync pixels', () => {
+ const response = spec.getUserSyncs({}, [ { body: rtbResponse } ]);
+ expect(Array.isArray(response)).to.equal(true);
+ expect(response.length).to.equal(4);
+ expect(response[ 0 ].type).to.equal(rtbResponse.ext.pixels[ 0 ].type);
+ expect(response[ 0 ].url).to.equal(rtbResponse.ext.pixels[ 0 ].url);
+ expect(response[ 1 ].type).to.equal(rtbResponse.ext.pixels[ 1 ].type);
+ expect(response[ 1 ].url).to.equal(rtbResponse.ext.pixels[ 1 ].url);
+ expect(response[ 2 ].type).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].ext.pixels[ 0 ].type);
+ expect(response[ 2 ].url).to.equal(rtbResponse.seatbid[ 0 ].bid[ 0 ].ext.pixels[ 0 ].url);
+ expect(response[ 3 ].type).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].ext.pixels[ 0 ].type);
+ expect(response[ 3 ].url).to.equal(rtbResponse.seatbid[ 1 ].bid[ 0 ].ext.pixels[ 0 ].url);
+ });
+ });
+});