-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Create yieldmoBidAdapter file * Copy over TL adapter and change name spacing * Update bid adapter naming to Yieldmo * Init tests for yieldmoBidAdapter * Add yeildmo config to pbjs_example_gpt * feature/yieldmoBidAdapter: added request build * Update ym response to have placement and impression level info * Remove environment param * Update ym tests for single bid request structure * Update url to use _ instead of camelcase * Update YMCB to handle multiple placements in one response * Clean up and remove TODO from adapter * Update response tests to work with single response structure * Remove trailing space * Cleanup * Adjusted code according to CR comments * Update bid adapter with fallback for incorrect bid response * Update yeildmo prebid endpoint * Add check to make sure response is an Array * Remove environment tracking as we are no going to use this * Update test to pass with new Yieldmo endpoint * Update return obj and remove node debug comments * Remove changes to hello_world and yarn.lock files * Remove unneeded comments
- Loading branch information
1 parent
f57f337
commit 598817f
Showing
3 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
var utils = require('src/utils.js'); | ||
var adloader = require('src/adloader.js'); | ||
var bidmanager = require('src/bidmanager.js'); | ||
var bidfactory = require('src/bidfactory.js'); | ||
var adaptermanager = require('src/adaptermanager'); | ||
|
||
/** | ||
* Adapter for requesting bids from Yieldmo. | ||
* | ||
* @returns {{callBids: _callBids}} | ||
* @constructor | ||
*/ | ||
|
||
var YieldmoAdapter = function YieldmoAdapter() { | ||
function _callBids(params) { | ||
var bids = params.bids; | ||
adloader.loadScript(buildYieldmoCall(bids)); | ||
} | ||
|
||
function buildYieldmoCall(bids) { | ||
// build our base tag, based on if we are http or https | ||
var ymURI = '//bid.yieldmo.com/exchange/prebid?'; | ||
var ymCall = document.location.protocol + ymURI; | ||
|
||
// Placement specific information | ||
ymCall = _appendPlacementInformation(ymCall, bids); | ||
|
||
// General impression params | ||
ymCall = _appendImpressionInformation(ymCall); | ||
|
||
// remove the trailing "&" | ||
if (ymCall.lastIndexOf('&') === ymCall.length - 1) { | ||
ymCall = ymCall.substring(0, ymCall.length - 1); | ||
} | ||
|
||
utils.logMessage('ymCall request built: ' + ymCall); | ||
|
||
return ymCall; | ||
} | ||
|
||
function _appendPlacementInformation(url, bids) { | ||
var placements = []; | ||
var placement; | ||
var bid; | ||
|
||
for (var i = 0; i < bids.length; i++) { | ||
bid = bids[i]; | ||
|
||
placement = {}; | ||
placement.callback_id = bid.bidId; | ||
placement.placement_id = bid.placementCode; | ||
placement.sizes = bid.sizes; | ||
|
||
placements.push(placement); | ||
} | ||
|
||
url = utils.tryAppendQueryString(url, 'p', JSON.stringify(placements)); | ||
return url; | ||
} | ||
|
||
function _appendImpressionInformation(url) { | ||
var page_url = document.location; // page url | ||
var pr = document.referrer || ''; // page's referrer | ||
var dnt = (navigator.doNotTrack || false).toString(); // true if user enabled dnt (false by default) | ||
var _s = document.location.protocol === 'https:' ? 1 : 0; // 1 if page is secure | ||
var description = _getPageDescription(); | ||
var title = document.title || ''; // Value of the title from the publisher's page. | ||
var bust = new Date().getTime().toString(); // cache buster | ||
var scrd = window.devicePixelRatio || 0; // screen pixel density | ||
|
||
url = utils.tryAppendQueryString(url, 'callback', '$$PREBID_GLOBAL$$.YMCB'); | ||
url = utils.tryAppendQueryString(url, 'page_url', page_url); | ||
url = utils.tryAppendQueryString(url, 'pr', pr); | ||
url = utils.tryAppendQueryString(url, 'bust', bust); | ||
url = utils.tryAppendQueryString(url, '_s', _s); | ||
url = utils.tryAppendQueryString(url, 'scrd', scrd); | ||
url = utils.tryAppendQueryString(url, 'dnt', dnt); | ||
url = utils.tryAppendQueryString(url, 'description', description); | ||
url = utils.tryAppendQueryString(url, 'title', title); | ||
|
||
return url; | ||
} | ||
|
||
function _getPageDescription() { | ||
if (document.querySelector('meta[name="description"]')) { | ||
return document.querySelector('meta[name="description"]').getAttribute('content'); // Value of the description metadata from the publisher's page. | ||
} else { | ||
return ''; | ||
} | ||
} | ||
|
||
// expose the callback to the global object: | ||
$$PREBID_GLOBAL$$.YMCB = function(ymResponses) { | ||
if (ymResponses && ymResponses.constructor === Array && ymResponses.length > 0) { | ||
for (var i = 0; i < ymResponses.length; i++) { | ||
_registerPlacementBid(ymResponses[i]); | ||
} | ||
} else { | ||
// If an incorrect response is returned, register error bids for all placements | ||
// to prevent Prebid waiting till timeout for response | ||
_registerNoResponseBids(); | ||
|
||
utils.logMessage('No prebid response for placement %%PLACEMENT%%'); | ||
} | ||
}; | ||
|
||
function _registerPlacementBid(response) { | ||
var bidObj = utils.getBidRequest(response.callback_id); | ||
var placementCode = bidObj && bidObj.placementCode; | ||
var bid = []; | ||
|
||
if (response && response.cpm && response.cpm !== 0) { | ||
bid = bidfactory.createBid(1, bidObj); | ||
bid.bidderCode = 'yieldmo'; | ||
bid.cpm = response.cpm; | ||
bid.ad = response.ad; | ||
bid.width = response.width; | ||
bid.height = response.height; | ||
bidmanager.addBidResponse(placementCode, bid); | ||
} else { | ||
// no response data | ||
if (bidObj) { utils.logMessage('No prebid response from yieldmo for placementCode: ' + bidObj.placementCode); } | ||
bid = bidfactory.createBid(2, bidObj); | ||
bid.bidderCode = 'yieldmo'; | ||
bidmanager.addBidResponse(placementCode, bid); | ||
} | ||
} | ||
|
||
function _registerNoResponseBids() { | ||
var yieldmoBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bid => bid.bidderCode === 'yieldmo'); | ||
|
||
utils._each(yieldmoBidRequests.bids, function (currentBid) { | ||
var bid = []; | ||
bid = bidfactory.createBid(2, currentBid); | ||
bid.bidderCode = 'yieldmo'; | ||
bidmanager.addBidResponse(currentBid.placementCode, bid); | ||
}); | ||
} | ||
|
||
return Object.assign(this, { | ||
callBids: _callBids | ||
}); | ||
}; | ||
|
||
adaptermanager.registerBidAdapter(new YieldmoAdapter(), 'yieldmo'); | ||
|
||
module.exports = YieldmoAdapter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
import {expect} from 'chai'; | ||
import Adapter from '../../../modules/yieldmoBidAdapter'; | ||
import bidManager from '../../../src/bidmanager'; | ||
import adLoader from '../../../src/adloader'; | ||
import {parse as parseURL} from '../../../src/url'; | ||
|
||
describe('Yieldmo adapter', () => { | ||
let bidsRequestedOriginal; | ||
let adapter; | ||
let sandbox; | ||
|
||
const bidderRequest = { | ||
bidderCode: 'yieldmo', | ||
bids: [ | ||
{ | ||
bidId: 'bidId1', | ||
bidder: 'yieldmo', | ||
placementCode: 'foo', | ||
sizes: [[728, 90]] | ||
}, | ||
{ | ||
bidId: 'bidId2', | ||
bidder: 'yieldmo', | ||
placementCode: 'bar', | ||
sizes: [[300, 600], [300, 250]] | ||
} | ||
] | ||
}; | ||
|
||
beforeEach(() => { | ||
bidsRequestedOriginal = $$PREBID_GLOBAL$$._bidsRequested; | ||
$$PREBID_GLOBAL$$._bidsRequested = []; | ||
|
||
adapter = new Adapter(); | ||
sandbox = sinon.sandbox.create(); | ||
}); | ||
|
||
afterEach(() => { | ||
sandbox.restore(); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested = bidsRequestedOriginal; | ||
}); | ||
|
||
describe('callBids', () => { | ||
let bidRequestURL; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(adLoader, 'loadScript'); | ||
adapter.callBids(bidderRequest); | ||
|
||
bidRequestURL = adLoader.loadScript.firstCall.args[0]; | ||
}); | ||
|
||
it('should load a script with passed bid params', () => { | ||
let route = 'http://bid.yieldmo.com/exchange/prebid?'; | ||
let requestParams = parseURL(bidRequestURL).search; | ||
let parsedPlacementParams = JSON.parse(decodeURIComponent(requestParams.p)); | ||
|
||
sinon.assert.calledOnce(adLoader.loadScript); | ||
expect(bidRequestURL).to.contain(route); | ||
|
||
// placement 1 | ||
expect(parsedPlacementParams[0]).to.have.property('callback_id', 'bidId1'); | ||
expect(parsedPlacementParams[0]).to.have.property('placement_id', 'foo'); | ||
expect(parsedPlacementParams[0].sizes[0][0]).to.equal(728); | ||
expect(parsedPlacementParams[0].sizes[0][1]).to.equal(90); | ||
|
||
// placement 2 | ||
expect(parsedPlacementParams[1]).to.have.property('callback_id', 'bidId2'); | ||
expect(parsedPlacementParams[1]).to.have.property('placement_id', 'bar'); | ||
expect(parsedPlacementParams[1].sizes[0][0]).to.equal(300); | ||
expect(parsedPlacementParams[1].sizes[0][1]).to.equal(600); | ||
expect(parsedPlacementParams[1].sizes[1][0]).to.equal(300); | ||
expect(parsedPlacementParams[1].sizes[1][1]).to.equal(250); | ||
|
||
// impression information | ||
expect(requestParams).to.have.property('callback', '$$PREBID_GLOBAL$$.YMCB'); | ||
expect(requestParams).to.have.property('page_url'); | ||
}); | ||
}); | ||
|
||
describe('YMCB', () => { | ||
it('should exist and be a function', () => { | ||
expect($$PREBID_GLOBAL$$.YMCB).to.exist.and.to.be.a('function'); | ||
}); | ||
}); | ||
|
||
describe('add bids to the manager', () => { | ||
let firstBid; | ||
let secondBid; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(bidManager, 'addBidResponse'); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); | ||
|
||
// respond | ||
let bidderReponse = [{ | ||
'cpm': 3.45455, | ||
'width': 300, | ||
'height': 250, | ||
'callback_id': 'bidId1', | ||
'ad': '<html><head></head><body>HELLO YIELDMO AD</body></html>' | ||
}, { | ||
'cpm': 4.35455, | ||
'width': 400, | ||
'height': 350, | ||
'callback_id': 'bidId2', | ||
'ad': '<html><head></head><body>HELLO YIELDMO AD</body></html>' | ||
}]; | ||
|
||
$$PREBID_GLOBAL$$.YMCB(bidderReponse); | ||
|
||
firstBid = bidManager.addBidResponse.firstCall.args[1]; | ||
secondBid = bidManager.addBidResponse.secondCall.args[1]; | ||
}); | ||
|
||
it('should add a bid object for each bid', () => { | ||
sinon.assert.calledTwice(bidManager.addBidResponse); | ||
}); | ||
|
||
it('should pass the correct placement code as first param', () => { | ||
let firstPlacementCode = bidManager.addBidResponse.firstCall.args[0]; | ||
let secondPlacementCode = bidManager.addBidResponse.secondCall.args[0]; | ||
|
||
expect(firstPlacementCode).to.eql('foo'); | ||
expect(secondPlacementCode).to.eql('bar'); | ||
}); | ||
|
||
it('should have a good statusCode', () => { | ||
expect(firstBid.getStatusCode()).to.eql(1); | ||
expect(secondBid.getStatusCode()).to.eql(1); | ||
}); | ||
|
||
it('should add the CPM to the bid object', () => { | ||
expect(firstBid).to.have.property('cpm', 3.45455); | ||
expect(secondBid).to.have.property('cpm', 4.35455); | ||
}); | ||
|
||
it('should add the bidder code to the bid object', () => { | ||
expect(firstBid).to.have.property('bidderCode', 'yieldmo'); | ||
expect(secondBid).to.have.property('bidderCode', 'yieldmo'); | ||
}); | ||
|
||
it('should include the ad on the bid object', () => { | ||
expect(firstBid).to.have.property('ad'); | ||
expect(secondBid).to.have.property('ad'); | ||
}); | ||
|
||
it('should include the size on the bid object', () => { | ||
expect(firstBid).to.have.property('width', 300); | ||
expect(firstBid).to.have.property('height', 250); | ||
expect(secondBid).to.have.property('width', 400); | ||
expect(secondBid).to.have.property('height', 350); | ||
}); | ||
}); | ||
|
||
describe('add empty bids if no bid returned', () => { | ||
let firstBid; | ||
let secondBid; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(bidManager, 'addBidResponse'); | ||
|
||
$$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); | ||
|
||
// respond | ||
let bidderReponse = [{ | ||
'status': 'no_bid', | ||
'callback_id': 'bidId1' | ||
}, { | ||
'status': 'no_bid', | ||
'callback_id': 'bidId2' | ||
}]; | ||
|
||
$$PREBID_GLOBAL$$.YMCB(bidderReponse); | ||
|
||
firstBid = bidManager.addBidResponse.firstCall.args[1]; | ||
secondBid = bidManager.addBidResponse.secondCall.args[1]; | ||
}); | ||
|
||
it('should add a bid object for each bid', () => { | ||
sinon.assert.calledTwice(bidManager.addBidResponse); | ||
}); | ||
|
||
it('should include the bid request bidId as the adId', () => { | ||
expect(firstBid).to.have.property('adId', 'bidId1'); | ||
expect(secondBid).to.have.property('adId', 'bidId2'); | ||
}); | ||
|
||
it('should have an error statusCode', () => { | ||
expect(firstBid.getStatusCode()).to.eql(2); | ||
expect(secondBid.getStatusCode()).to.eql(2); | ||
}); | ||
|
||
it('should pass the correct placement code as first param', () => { | ||
let firstPlacementCode = bidManager.addBidResponse.firstCall.args[0]; | ||
let secondPlacementCode = bidManager.addBidResponse.secondCall.args[0]; | ||
|
||
expect(firstPlacementCode).to.eql('foo'); | ||
expect(secondPlacementCode).to.eql('bar'); | ||
}); | ||
|
||
it('should add the bidder code to the bid object', () => { | ||
expect(firstBid).to.have.property('bidderCode', 'yieldmo'); | ||
expect(secondBid).to.have.property('bidderCode', 'yieldmo'); | ||
}); | ||
}); | ||
}); |