diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js new file mode 100644 index 00000000000..9f94b5b815e --- /dev/null +++ b/modules/yieldoneBidAdapter.js @@ -0,0 +1,71 @@ +import * as utils from 'src/utils'; +import {config} from 'src/config'; +import {registerBidder} from 'src/adapters/bidderFactory'; + +const BIDDER_CODE = 'yieldone'; +const ENDPOINT_URL = '//y.one.impact-ad.jp/h_bid'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['y1'], + isBidRequestValid: function(bid) { + return !!(bid.params.placementId); + }, + buildRequests: function(validBidRequests) { + return validBidRequests.map(bidRequest => { + const params = bidRequest.params; + const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; + const width = sizes.split('x')[0]; + const height = sizes.split('x')[1]; + const placementId = params.placementId; + const cb = Math.floor(Math.random() * 99999999999); + const referrer = encodeURIComponent(utils.getTopWindowUrl()); + const bidId = bidRequest.bidId; + const payload = { + v: 'hb1', + p: placementId, + w: width, + h: height, + cb: cb, + r: referrer, + uid: bidId, + t: 'i' + }; + return { + method: 'GET', + url: ENDPOINT_URL, + data: payload, + } + }); + }, + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + const response = serverResponse.body; + const crid = response.crid || 0; + const width = response.width || 0; + const height = response.height || 0; + const cpm = response.cpm * 1000 || 0; + if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) { + const dealId = response.dealid || ''; + const currency = response.currency || 'JPY'; + const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; + const referrer = utils.getTopWindowUrl(); + const bidResponse = { + requestId: bidRequest.data.uid, + cpm: cpm, + width: response.width, + height: response.height, + creativeId: crid, + dealId: dealId, + currency: currency, + netRevenue: netRevenue, + ttl: config.getConfig('_bidderTimeout'), + referrer: referrer, + ad: response.adTag + }; + bidResponses.push(bidResponse); + } + return bidResponses; + } +} +registerBidder(spec); diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md new file mode 100644 index 00000000000..f1f48637927 --- /dev/null +++ b/modules/yieldoneBidAdapter.md @@ -0,0 +1,27 @@ +# Overview + +``` +Module Name: YIELDONE Bidder Adapter +Module Type: Bidder Adapter +Maintainer: y1dev@platform-one.co.jp +``` + +# Description + +Connect to YIELDONE for bids. + +THE YIELDONE adapter requires setup and approval from the Rubicon Project team. Please reach out to your account team or y1s@platform-one.co.jp for more information. + +# Test Parameters +``` + var adUnits = [{ + code: 'banner-ad-div', + sizes: [[300, 250]], + bids: [{ + bidder: 'yieldone', + params: { + placementId: '44082' + } + }] + }]; +``` diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js new file mode 100644 index 00000000000..e763257f097 --- /dev/null +++ b/test/spec/modules/yieldoneBidAdapter_spec.js @@ -0,0 +1,147 @@ +import { expect } from 'chai'; +import { spec } from 'modules/yieldoneBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +const ENDPOINT = '//y.one.impact-ad.jp/h_bid'; + +describe('yieldoneBidAdapter', function() { + const adapter = newBidder(spec); + + describe('isBidRequestValid', () => { + let bid = { + 'bidder': 'yieldone', + 'params': { + placementId: '44082' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '23beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when placementId not passed correctly', () => { + bid.params.placementId = ''; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when require params are not passed', () => { + let bid = Object.assign({}, bid); + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + let bidRequests = [ + { + 'bidder': 'yieldone', + 'params': { + placementId: '44082' + }, + 'adUnitCode': 'adunit-code1', + 'sizes': [ + [300, 250] + ], + 'bidId': '23beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }, + { + 'bidder': 'yieldone', + 'params': { + placementId: '44337' + }, + 'adUnitCode': 'adunit-code2', + 'sizes': [ + [300, 250] + ], + 'bidId': '382091349b149f"', + 'bidderRequestId': '"1f9c98192de251"', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + } + ]; + + const request = spec.buildRequests(bidRequests); + + it('sends bid request to our endpoint via GET', () => { + expect(request[0].method).to.equal('GET'); + expect(request[1].method).to.equal('GET'); + }); + + it('attaches source and version to endpoint URL as query params', () => { + expect(request[0].url).to.equal(ENDPOINT); + expect(request[1].url).to.equal(ENDPOINT); + }); + }); + + describe('interpretResponse', () => { + let bidRequest = [ + { + 'method': 'GET', + 'url': '//y.one.impact-ad.jp/h_bid', + 'data': { + 'v': 'hb1', + 'p': '44082', + 'w': '300', + 'h': '250', + 'cb': 12892917383, + 'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836', + 'uid': '23beaa6af6cdde', + 't': 'i' + } + } + ]; + + let serverResponse = { + body: { + 'adTag': '', + 'cpm': 0.0536616, + 'crid': '2494768', + 'statusMessage': 'Bid available', + 'uid': '23beaa6af6cdde', + 'width': 300, + 'height': 250 + } + }; + + it('should get the correct bid response', () => { + let expectedResponse = [{ + 'requestId': '23beaa6af6cdde', + 'cpm': 53.6616, + 'width': 300, + 'height': 250, + 'creativeId': '2494768', + 'dealId': '', + 'currency': 'JPY', + 'netRevenue': true, + 'ttl': 3000, + 'referrer': '', + 'ad': '' + }]; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); + }); + + it('handles empty bid response', () => { + let response = { + body: { + 'uid': '2c0b634db95a01', + 'height': 0, + 'crid': '', + 'statusMessage': 'Bid returned empty or error response', + 'width': 0, + 'cpm': 0 + } + }; + let result = spec.interpretResponse(response, bidRequest[0]); + expect(result.length).to.equal(0); + }); + }); +});