diff --git a/modules/viBidAdapter.js b/modules/viBidAdapter.js new file mode 100644 index 00000000000..bcfc4e246ac --- /dev/null +++ b/modules/viBidAdapter.js @@ -0,0 +1,69 @@ +import * as utils from 'src/utils'; +import { registerBidder } from 'src/adapters/bidderFactory'; +import { BANNER } from 'src/mediaTypes'; + +const BIDDER_CODE = 'vi'; +const SUPPORTED_MEDIA_TYPES = [BANNER]; + +function isBidRequestValid(bid) { + return !!(bid.params.pubId); +} + +function buildRequests(bidReqs) { + let imps = []; + utils._each(bidReqs, function (bid) { + imps.push({ + id: bid.bidId, + sizes: utils.parseSizesInput(bid.sizes).map(size => size.split('x')), + bidFloor: parseFloat(bid.params.bidFloor) > 0 ? bid.params.bidFloor : 0 + }); + }); + + const bidRequest = { + id: bidReqs[0].requestId, + imps: imps, + publisherId: utils.getBidIdParameter('pubId', bidReqs[0].params), + siteId: utils.getBidIdParameter('siteId', bidReqs[0].params), + cat: utils.getBidIdParameter('cat', bidReqs[0].params), + language: utils.getBidIdParameter('lang', bidReqs[0].params), + domain: utils.getTopWindowLocation().hostname, + page: utils.getTopWindowUrl(), + referrer: utils.getTopWindowReferrer() + }; + return { + method: 'POST', + url: `//pb.vi-serve.com/prebid/bid`, + data: JSON.stringify(bidRequest), + options: {contentType: 'application/json', withCredentials: false} + }; +} + +function interpretResponse(bids) { + let responses = []; + utils._each(bids.body, function(bid) { + responses.push({ + requestId: bid.id, + cpm: parseFloat(bid.price), + width: parseInt(bid.width, 10), + height: parseInt(bid.height, 10), + creativeId: bid.creativeId, + dealId: bid.dealId || null, + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ad: decodeURIComponent(`${bid.ad}`), + ttl: 60000 + }); + }); + return responses; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + isBidRequestValid, + buildRequests, + interpretResponse +} + +registerBidder(spec); diff --git a/modules/viBidAdapter.md b/modules/viBidAdapter.md new file mode 100644 index 00000000000..23288024fcc --- /dev/null +++ b/modules/viBidAdapter.md @@ -0,0 +1,41 @@ +# Overview + +``` +Module Name: vi bid adapter +Module Type: Bidder adapter +Maintainer: support@vi.ai +``` + +# Description + +The video intelligence (vi) adapter integration to the Prebid library. +Connects to vi’s demand sources. +There should be only one ad unit with vi bid adapter on each single page. + +# Test Parameters + +``` +var adUnits = [{ + code: 'div-0', + sizes: [[320, 480]], + bids: [{ + bidder: 'vi', + params: { + pubId: 'sb_test', + lang: 'en-US', + cat: 'IAB1', + bidFloor: 0.05 //optional + } + }] +}]; +``` + +# Parameters + +| Name | Scope | Description | Example | +| :------------ | :------- | :---------------------------------------------- | :--------------------------------- | +| `pubId` | required | Publisher ID, provided by vi | 'sb_test' | +| `lang` | required | Ad language, in ISO 639-1 language code format | 'en-US', 'es-ES', 'de' | +| `cat` | required | Ad IAB category (top-level or subcategory), single one supported | 'IAB1', 'IAB9-1' | +| `bidFloor` | optional | Lowest value of expected bid price | 0.001 | + diff --git a/test/spec/modules/viBidAdapter_spec.js b/test/spec/modules/viBidAdapter_spec.js new file mode 100644 index 00000000000..e8b0fbcc4b2 --- /dev/null +++ b/test/spec/modules/viBidAdapter_spec.js @@ -0,0 +1,139 @@ +import { expect } from 'chai'; +import { spec } from 'modules/viBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +const ENDPOINT = `//pb.vi-serve.com/prebid/bid`; + +describe('viBidAdapter', function() { + newBidder(spec); + + describe('isBidRequestValid', () => { + let bid = { + 'bidder': 'vi', + 'params': { + 'pubId': 'sb_test', + 'lang': 'en-US', + 'cat': 'IAB1', + 'bidFloor': 0.05 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [320, 480] + ], + 'bidId': '29b891ad542377', + 'bidderRequestId': '1dc9a08206a57b', + 'requestId': '24176695-e3f0-44db-815b-ed97cf5ad49b', + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '474da635-9cf0-4188-a3d9-58961be8f905' + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when pubId not passed', () => { + bid.params.pubId = undefined; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + let bidRequests = [{ + 'bidder': 'vi', + 'params': { + 'pubId': 'sb_test', + 'lang': 'en-US', + 'cat': 'IAB1', + 'bidFloor': 0.05 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [320, 480] + ], + 'bidId': '29b891ad542377', + 'bidderRequestId': '1dc9a08206a57b', + 'requestId': '24176695-e3f0-44db-815b-ed97cf5ad49b', + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '474da635-9cf0-4188-a3d9-58961be8f905' + }]; + + const request = spec.buildRequests(bidRequests); + + it('POST bid request to vi', () => { + expect(request.method).to.equal('POST'); + }); + + it('check endpoint URL', () => { + expect(request.url).to.equal(ENDPOINT) + }); + }); + + describe('buildRequests can handle size in 1-dim array', () => { + let bidRequests = [{ + 'bidder': 'vi', + 'params': { + 'pubId': 'sb_test', + 'lang': 'en-US', + 'cat': 'IAB1', + 'bidFloor': 0.05 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [320, 480], + 'bidId': '29b891ad542377', + 'bidderRequestId': '1dc9a08206a57b', + 'requestId': '24176695-e3f0-44db-815b-ed97cf5ad49b', + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '474da635-9cf0-4188-a3d9-58961be8f905' + }]; + + const request = spec.buildRequests(bidRequests); + + it('POST bid request to vi', () => { + expect(request.method).to.equal('POST'); + }); + + it('check endpoint URL', () => { + expect(request.url).to.equal(ENDPOINT) + }); + }); + + describe('interpretResponse', () => { + let response = { + body: [{ + 'id': '29b891ad542377', + 'price': 0.1, + 'width': 320, + 'height': 480, + 'ad': '', + 'creativeId': 'dZsPGv' + }] + }; + + it('should get the correct bid response', () => { + let expectedResponse = [{ + 'requestId': '29b891ad542377', + 'cpm': 0.1, + 'width': 320, + 'height': 480, + 'creativeId': 'dZsPGv', + 'dealId': null, + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ad': decodeURIComponent(``), + 'ttl': 60000 + }]; + + let result = spec.interpretResponse(response); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + }); + + it('handles empty bid response', () => { + let response = { + body: [] + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); +});