Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yieldbot adunit bidder params slot name usage fix #1394

Merged
merged 2 commits into from
Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Yieldbot adunit bidder params slot name usage fix, PR feedback++
  • Loading branch information
John W. Ellis committed Aug 21, 2017
commit cd68636f6f457ff70992cfc9c3d8ef7cf03b0045
8 changes: 4 additions & 4 deletions modules/yieldbotBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ function YieldbotAdapter() {
var bid = v;
// bidder params config: http://prebid.org/dev-docs/bidders/yieldbot.html
// - last psn wins
psn = bid.params && bid.params.psn || psn;
var slotName = bid.params && bid.params.slot || 'ERROR_PREBID_DEFINE_YB_SLOT';
psn = bid.params && bid.params.psn ? bid.params.psn : psn;
var slotName = bid.params && bid.params.slot ? bid.params.slot : 'ERROR_PREBID_DEFINE_YB_SLOT';
var parsedSizes = utils.parseSizesInput(bid.sizes) || [];
slots[slotName] = slots[slotName] || [];
slots[slotName] = slots[slotName].concat(parsedSizes);
Expand All @@ -138,12 +138,12 @@ function YieldbotAdapter() {
yieldbot.pub(psn);
for (var slotName in slots) {
if (slots.hasOwnProperty(slotName)) {
yieldbot.defineSlot(slotName, { sizes: slots[slotName]});
yieldbot.defineSlot(slotName, { sizes: slots[slotName] });
}
}
yieldbot.enableAsync();
yieldbot.go();
} else {
} else if (!utils.isEmpty(slots)) {
yieldbot.nextPageview(slots);
}
});
Expand Down
166 changes: 103 additions & 63 deletions test/spec/modules/yieldbotBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ function createYieldbotMockLib() {
pub: (psn) => {},
defineSlot: (slotName, optionalDomIdOrConfigObject, optionalTime) => {},
enableAsync: () => {},
go: () => { window.yieldbot._initialized = true; },
go: () => {},
nextPageview: (slots, callback) => {},
getSlotCriteria: (slotName) => {
return YB_BID_FIXTURE[slotName] || {ybot_ad: 'n'};
}
getSlotCriteria: (slotName) => {}
};
}

Expand All @@ -83,44 +81,68 @@ function mockYieldbotBidRequest() {
window.ybotq = [];
}

const refreshSuiteRegex = /refresh$/;
const localSetupTestRegex = /localSetupTest$/;
const MAKE_BID_REQUEST = true;
let sandbox;
let bidManagerStub;
let yieldbotLibStub;

function setupTest(testRequest) {
/**
* Test initialization hook. Makes initial adapter and mock bid requests<br>
* unless the test is a special case with "localSetupTest". <br>
* 1. All suite tests are initialized with required mocks and stubs<br>
* 2. If the test title does <em>not</em> end in "localSetupTest", adapter and
* mock bid requests are executed
* 3. Test titles ending in "localSetupTest" are special case tests and are
* expected to call <code>setupTest(object, MAKE_BID_REQUEST)</code> where
* applicable
* @param {object} testRequest bidder request bids fixture
* @param {boolean} force trigger adapter callBids and Yieldbot library request
* @private
*/
function setupTest(testRequest, force = false) {
sandbox = sinon.sandbox.create();

createYieldbotMockLib();

sandbox.stub(adLoader, 'loadScript');
yieldbotLibStub = sandbox.stub(window.yieldbot);
yieldbotLibStub.getSlotCriteria.restore();

if (this && this.currentTest.parent.title.match(refreshSuiteRegex)) {
yieldbotLibStub.go.restore();
}
yieldbotLibStub = {};
yieldbotLibStub.nextPageview = sandbox.stub(window.yieldbot, 'nextPageview');
yieldbotLibStub.defineSlot = sandbox.stub(window.yieldbot, 'defineSlot');
yieldbotLibStub.pub = sandbox.stub(window.yieldbot, 'pub');
yieldbotLibStub.enableAsync = sandbox.stub(window.yieldbot, 'enableAsync');

yieldbotLibStub.getSlotCriteria =
sandbox.stub(
window.yieldbot,
'getSlotCriteria',
(slotName) => {
return YB_BID_FIXTURE[slotName] || {ybot_ad: 'n'};
});

yieldbotLibStub.go =
sandbox.stub(
window.yieldbot,
'go',
() => {
window.yieldbot._initialized = true;
});

bidManagerStub = sandbox.stub(bidManager, 'addBidResponse');

const ybAdapter = new YieldbotAdapter();
let request = testRequest || cloneJson(bidderRequest);
ybAdapter.callBids(request);
mockYieldbotBidRequest();
if ((this && !this.currentTest.parent.title.match(localSetupTestRegex)) || force === MAKE_BID_REQUEST) {
ybAdapter.callBids(request);
mockYieldbotBidRequest();
}
return { adapter: ybAdapter, localRequest: request };
}

function removeBids(bidder) {
if (window && window.pbjs) {
window.pbjs._bidsRequested = window.pbjs._bidsRequested.filter(o => {
return o.bidderCode !== bidder;
});
}
}
function restoreTest() {
sandbox.restore();
restoreYieldbotMockLib();
removeBids('yieldbot');
}

describe('Yieldbot adapter tests', function() {
Expand Down Expand Up @@ -162,11 +184,6 @@ describe('Yieldbot adapter tests', function() {
expect(sizes).to.deep.equal([]);
});

it('should return [] for function sizes', function() {
const sizes = adapter.getUniqueSlotSizes(function () {});
expect(sizes).to.deep.equal([]);
});

it('should return [] for number sizes', function() {
const sizes = adapter.getUniqueSlotSizes(1111);
expect(sizes).to.deep.equal([]);
Expand Down Expand Up @@ -215,14 +232,20 @@ describe('Yieldbot adapter tests', function() {
sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'leaderboard', {sizes: [['728', '90'], ['970', '90']]});
});

it('should not use inherited Object properties', function() {
restoreTest();

it('should not use inherited Object properties, localSetupTest', function() {
let oProto = Object.prototype;
oProto.superProp = ['300', '250'];

expect(Object.prototype.superProp).to.be.an('array');
setupTest(localRequest);
localRequest.bids.forEach((bid) => {
expect(bid.superProp).to.be.an('array');
});

expect(YB_BID_FIXTURE.medrec.superProp).to.deep.equal(['300', '250']);
expect(YB_BID_FIXTURE.leaderboard.superProp).to.deep.equal(['300', '250']);

restoreTest();
setupTest(localRequest, MAKE_BID_REQUEST);

sinon.assert.neverCalledWith(yieldbotLibStub.defineSlot, 'superProp', {sizes: ['300', '250']});
sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'medrec', {sizes: [['300', '250'], ['300', '600']]});
Expand Down Expand Up @@ -263,23 +286,37 @@ describe('Yieldbot adapter tests', function() {
expect(pb_bid2.statusMessage).to.match(/empty.*response/);
});

it('should validate slot dimensions', function() {
it('should validate slot dimensions, localSetupTest', function() {
let invalidSizeBid = {
bidId: '2640ad280208ce',
sizes: [[728, 90]],
sizes: [[728, 90], [300, 250], [970, 90]],
bidder: 'yieldbot',
bidderRequestId: '187a340cb9ccc3',
params: { psn: '1234', slot: 'medrec' },
requestId: '5f297a1f-3163-46c2-854f-b55fd2e74ec3',
placementCode: '/4294967296/adunit3'
};

let localBidderRequest = cloneJson(localRequest);
localBidderRequest.bids.push(invalidSizeBid);
const bidResponseMedrec = {
bidderCode: 'yieldbot',
width: '300',
height: '250',
statusMessage: 'Bid available',
cpm: 2,
ybot_ad: 'y',
ybot_slot: 'medrec',
ybot_cpm: '200',
ybot_size: '300x250'
};

localRequest.bids = [invalidSizeBid];
restoreTest();
setupTest(localRequest, MAKE_BID_REQUEST);

const adapter = new YieldbotAdapter();
adapter.callBids(localBidderRequest);
mockYieldbotBidRequest();
let bidManagerFirstCall = bidManagerStub.firstCall;

expect(bidManagerFirstCall.args[0]).to.equal('/4294967296/adunit3');
expect(bidManagerFirstCall.args[1]).to.include(bidResponseMedrec);
});

it('should make slot bid available once only', function() {
Expand Down Expand Up @@ -331,8 +368,6 @@ describe('Yieldbot adapter tests', function() {
sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'medrec');
sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'leaderboard');

removeBids('yieldbot');

const refreshBids = localRequest.bids.filter((object) => { return object.placementCode === '/4294967296/adunit1'; });
let refreshRequest = cloneJson(localRequest);
refreshRequest.bids = refreshBids;
Expand All @@ -347,6 +382,9 @@ describe('Yieldbot adapter tests', function() {
});

it('should not repeat multiply defined slot sizes', function() {
// placementCode: '/4294967296/adunit0'
// placementCode: '/4294967296/adunit2'
// Both placements declare medrec:300x250
adapter.callBids(localRequest);
mockYieldbotBidRequest();

Expand All @@ -355,33 +393,15 @@ describe('Yieldbot adapter tests', function() {
sinon.assert.calledWithExactly(yieldbotLibStub.nextPageview, expectedSlots);
});

/**
* Keep test for regression. Yieldbot adapter no longer refers to $$PREBID_GLOBAL$$._bidsRequested
* @private
*/
it('should not throw on callBids without bidsRequested', function() {
expect(window.yieldbot._initialized).to.equal(true);

removeBids('yieldbot');

adapter.callBids(cloneJson(localRequest));
mockYieldbotBidRequest();
sinon.assert.calledOnce(yieldbotLibStub.nextPageview);
});

it('should not add empty bidResponse on callBids without bidsRequested', function() {
expect(window.yieldbot._initialized).to.equal(true);
expect(bidManagerStub.calledThrice).to.equal(true);

removeBids('yieldbot');

let bidResponses = window.$$PREBID_GLOBAL$$._bidsReceived.filter(o => {
return o.bidderCode === 'yieldbot';
});
expect(bidResponses.length).to.equal(0);

adapter.callBids(localRequest);
adapter.callBids({});
mockYieldbotBidRequest();
sinon.assert.calledOnce(yieldbotLibStub.nextPageview);

expect(bidManagerStub.calledThrice).to.equal(true); // the initial bids
sinon.assert.notCalled(yieldbotLibStub.nextPageview);
});

it('should validate slot dimensions', function() {
Expand All @@ -400,6 +420,12 @@ describe('Yieldbot adapter tests', function() {
mockYieldbotBidRequest();

expect(bidManagerStub.getCalls().length).to.equal(6);

let lastNextPageview = yieldbotLibStub.nextPageview.lastCall;
let nextPageviewSlots = lastNextPageview.args[0];
expect(nextPageviewSlots.medrec).to.deep.equal([['640', '480'], ['1024', '768']]);
expect(nextPageviewSlots.leaderboard).to.deep.equal([['640', '480'], ['1024', '768']]);

let fourthCall = bidManagerStub.getCall(3);
let fifthCall = bidManagerStub.getCall(4);
let sixthCall = bidManagerStub.getCall(5);
Expand All @@ -414,7 +440,7 @@ describe('Yieldbot adapter tests', function() {
expect(sixthCall.args[1]).to.include(bidResponseNone);
});

it('should make slot bid available once only', function() {
it('should not make requests for previously requested bids', function() {
const bidResponseMedrec = {
bidderCode: 'yieldbot',
width: '300',
Expand All @@ -434,10 +460,17 @@ describe('Yieldbot adapter tests', function() {
statusMessage: 'Bid returned empty or error response'
};

// Refresh #1
adapter.callBids(localRequest);
mockYieldbotBidRequest();

expect(bidManagerStub.getCalls().length).to.equal(6);

let lastNextPageview = yieldbotLibStub.nextPageview.lastCall;
let nextPageviewSlots = lastNextPageview.args[0];
expect(nextPageviewSlots.medrec).to.deep.equal([['300', '250'], ['300', '600']]);
expect(nextPageviewSlots.leaderboard).to.deep.equal([['728', '90'], ['970', '90']]);

let fourthCall = bidManagerStub.getCall(3);
let fifthCall = bidManagerStub.getCall(4);
let sixthCall = bidManagerStub.getCall(5);
Expand All @@ -457,10 +490,17 @@ describe('Yieldbot adapter tests', function() {
let bidForNinethCall = localRequest.bids[localRequest.bids.length - 1];
bidForNinethCall.sizes = [[300, 250]];

// Refresh #2
adapter.callBids(localRequest);
mockYieldbotBidRequest();

expect(bidManagerStub.getCalls().length).to.equal(9);

lastNextPageview = yieldbotLibStub.nextPageview.lastCall;
nextPageviewSlots = lastNextPageview.args[0];
expect(nextPageviewSlots.medrec).to.deep.equal([['640', '480'], ['1024', '768'], ['300', '250']]);
expect(nextPageviewSlots.leaderboard).to.deep.equal([['640', '480'], ['1024', '768']]);

let seventhCall = bidManagerStub.getCall(6);
let eighthCall = bidManagerStub.getCall(7);
let ninethCall = bidManagerStub.getCall(8);
Expand Down