diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js new file mode 100644 index 00000000000..6851a7d3bd5 --- /dev/null +++ b/modules/admixerBidAdapter.js @@ -0,0 +1,74 @@ +import * as utils from 'src/utils'; +import {registerBidder} from 'src/adapters/bidderFactory'; + +const BIDDER_CODE = 'admixer'; +const ENDPOINT_URL = '//inv-nets.admixer.net/prebid.1.0.aspx'; +export const spec = { + code: BIDDER_CODE, + aliases: [], + supportedMediaTypes: ['banner', 'video'], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!bid.params.zone; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {bidderRequest} - bidderRequest.bids[] is an array of AdUnits and bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function (bidderRequest) { + const payload = { + imps: [], + referrer: utils.getTopWindowUrl(), + }; + bidderRequest.forEach((bid) => { + if (bid.bidder === BIDDER_CODE) { + payload.imps.push(bid); + } + }); + const payloadString = JSON.stringify(payload); + return { + method: 'GET', + url: ENDPOINT_URL, + data: `data=${payloadString}`, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const bidResponses = []; + // loop through serverResponses { + try { + serverResponse = serverResponse.body; + serverResponse.forEach((bidResponse) => { + const bidResp = { + requestId: bidResponse.bidId, + cpm: bidResponse.cpm, + width: bidResponse.width, + height: bidResponse.height, + ad: bidResponse.ad, + ttl: bidResponse.ttl, + creativeId: bidResponse.creativeId, + netRevenue: bidResponse.netRevenue, + currency: bidResponse.currency, + vastUrl: bidResponse.vastUrl, + }; + bidResponses.push(bidResp); + }); + } catch (e) { + utils.logError(e); + } + return bidResponses; + } +}; +registerBidder(spec); diff --git a/modules/admixerBidAdapter.md b/modules/admixerBidAdapter.md new file mode 100644 index 00000000000..682f5629115 --- /dev/null +++ b/modules/admixerBidAdapter.md @@ -0,0 +1,52 @@ +# Overview + +Module Name: Admixer Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@admixer.net + +# Description + +Connects to Admixer demand source to fetch bids. +Banner and Video formats are supported. +Please use ```admixer``` as the bidder code. + +# Test Parameters +``` + var adUnits = [ + { + code: 'desktop-banner-ad-div', + sizes: [[300, 250]], // a display size + bids: [ + { + bidder: "admixer", + params: { + zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' + } + } + ] + },{ + code: 'mobile-banner-ad-div', + sizes: [[300, 50]], // a mobile size + bids: [ + { + bidder: "admixer", + params: { + zone: '62211486-c50b-4356-9f0f-411778d31fcc' + } + } + ] + },{ + code: 'video-ad', + sizes: [[300, 50]], + mediaType: 'video', + bids: [ + { + bidder: "admixer", + params: { + zone: 'ebeb1e79-8cb4-4473-b2d0-2e24b7ff47fd' + } + } + ] + }, + ]; +``` diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js new file mode 100644 index 00000000000..13312e3d24e --- /dev/null +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -0,0 +1,117 @@ +import {expect} from 'chai'; +import {spec} from 'modules/admixerBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory'; + +const BIDDER_CODE = 'admixer'; +const ENDPOINT_URL = '//inv-nets.admixer.net/prebid.1.0.aspx'; +const ZONE_ID = '2eb6bd58-865c-47ce-af7f-a918108c3fd2'; + +describe('AdmixerAdapter', () => { + const adapter = newBidder(spec); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.be.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', () => { + let bid = { + 'bidder': BIDDER_CODE, + 'params': { + 'zone': ZONE_ID + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'placementId': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + let bidRequests = [ + { + 'bidder': BIDDER_CODE, + 'params': { + 'zone': ZONE_ID + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should add referrer and imp to be equal bidRequest', () => { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data.substr(5)); + expect(payload.referrer).to.not.be.undefined; + expect(payload.imps[0]).to.deep.equal(bidRequests[0]); + }); + + it('sends bid request to ENDPOINT via GET', () => { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(ENDPOINT_URL); + expect(request.method).to.equal('GET'); + }); + }); + + describe('interpretResponse', () => { + let response = { + body: [{ + 'currency': 'USD', + 'cpm': 6.210000, + 'ad': '
ad
', + 'width': 300, + 'height': 600, + 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', + 'ttl': 360, + 'netRevenue': false, + 'bidId': '5e4e763b6bc60b' + }] + }; + + it('should get correct bid response', () => { + const body = response.body; + let expectedResponse = [ + { + 'requestId': body[0].bidId, + 'cpm': body[0].cpm, + 'creativeId': body[0].creativeId, + 'width': body[0].width, + 'height': body[0].height, + 'ad': body[0].ad, + 'vastUrl': undefined, + 'currency': body[0].currency, + 'netRevenue': body[0].netRevenue, + 'ttl': body[0].ttl, + } + ]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); + }); + + it('handles nobid responses', () => { + let response = []; + + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); +});