mk9-prebid
Version:
Header Bidding Management Library
1,257 lines (1,095 loc) • 116 kB
JavaScript
import {
getAdServerTargeting,
getBidRequests,
getBidResponses,
getBidResponsesFromAPI,
getTargetingKeys,
getTargetingKeysBidLandscape,
getAdUnits,
createBidReceived
} from 'test/fixtures/fixtures.js';
import { auctionManager, newAuctionManager } from 'src/auctionManager.js';
import { targeting, newTargeting, filters } from 'src/targeting.js';
import { config as configObj } from 'src/config.js';
import * as ajaxLib from 'src/ajax.js';
import * as auctionModule from 'src/auction.js';
import { registerBidder } from 'src/adapters/bidderFactory.js';
import { _sendAdToCreative } from 'src/secureCreatives.js';
import find from 'core-js-pure/features/array/find.js';
var assert = require('chai').assert;
var expect = require('chai').expect;
var utils = require('src/utils');
var adapterManager = require('src/adapterManager').default;
var events = require('src/events');
var CONSTANTS = require('src/constants.json');
// These bid adapters are required to be loaded for the following tests to work
require('modules/appnexusBidAdapter');
var config = require('test/fixtures/config.json');
$$PREBID_GLOBAL$$ = $$PREBID_GLOBAL$$ || {};
var adUnits = getAdUnits();
var adUnitCodes = getAdUnits().map(unit => unit.code);
var bidsBackHandler = function() {};
const timeout = 2000;
var auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout: timeout});
auction.getBidRequests = getBidRequests;
auction.getBidsReceived = getBidResponses;
auction.getAdUnits = getAdUnits;
auction.getAuctionStatus = function() { return auctionModule.AUCTION_COMPLETED }
function resetAuction() {
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: false });
auction.getBidRequests = getBidRequests;
auction.getBidsReceived = getBidResponses;
auction.getAdUnits = getAdUnits;
auction.getAuctionStatus = function() { return auctionModule.AUCTION_COMPLETED }
}
var Slot = function Slot(elementId, pathId) {
var slot = {
targeting: {},
getSlotElementId: function getSlotElementId() {
return elementId;
},
getAdUnitPath: function getAdUnitPath() {
return pathId;
},
setTargeting: function setTargeting(key, value) {
this.targeting[key] = Array.isArray(value) ? value : [value];
},
getTargeting: function getTargeting(key) {
return this.targeting[key] || [];
},
getTargetingKeys: function getTargetingKeys() {
return Object.getOwnPropertyNames(this.targeting);
},
clearTargeting: function clearTargeting() {
this.targeting = {};
return this;
}
};
slot.spySetTargeting = sinon.spy(slot, 'setTargeting');
slot.spyGetSlotElementId = sinon.spy(slot, 'getSlotElementId');
return slot;
};
var createSlotArray = function createSlotArray() {
return [
new Slot(config.adUnitElementIDs[0], config.adUnitCodes[0]),
new Slot(config.adUnitElementIDs[1], config.adUnitCodes[1]),
new Slot(config.adUnitElementIDs[2], config.adUnitCodes[2])
];
};
var createSlotArrayScenario2 = function createSlotArrayScenario2() {
var slot1 = new Slot(config.adUnitElementIDs[0], config.adUnitCodes[0]);
slot1.setTargeting('pos1', '750x350');
var slot2 = new Slot(config.adUnitElementIDs[1], config.adUnitCodes[0]);
slot2.setTargeting('gender', ['male', 'female']);
return [
slot1,
slot2
];
};
window.googletag = {
_slots: [],
_targeting: {},
pubads: function () {
var self = this;
return {
getSlots: function () {
return self._slots;
},
setSlots: function (slots) {
self._slots = slots;
},
setTargeting: function(key, arrayOfValues) {
self._targeting[key] = Array.isArray(arrayOfValues) ? arrayOfValues : [arrayOfValues];
},
getTargeting: function(key) {
return self._targeting[key] || [];
},
getTargetingKeys: function() {
return Object.getOwnPropertyNames(self._targeting);
},
clearTargeting: function() {
self._targeting = {};
}
};
}
};
var createTagAST = function() {
var tags = {};
tags[config.adUnitCodes[0]] = {
keywords: {}
};
return tags;
};
window.apntag = {
keywords: [],
tags: createTagAST(),
setKeywords: function(key, params, options) {
var self = this;
if (!self.tags.hasOwnProperty(key)) {
return;
}
self.tags[key].keywords = this.tags[key].keywords || {};
if (typeof options === 'object' && options !== null && options.overrideKeyValue === true) {
utils._each(params, function(param, id) {
self.tags[key].keywords[id] = param;
});
} else {
utils._each(params, function (param, id) {
if (!self.tags[key].keywords.hasOwnProperty(id)) {
self.tags[key].keywords[id] = param;
} else if (!utils.isArray(self.tags[key].keywords[id])) {
self.tags[key].keywords[id] = [self.tags[key].keywords[id]].concat(param);
} else {
self.tags[key].keywords[id] = self.tags[key].keywords[id].concat(param);
}
})
}
},
getTag: function(tagId) {
return this.tags[tagId];
},
modifyTag: function(tagId, params) {
var output = {};
utils._each(this.tags[tagId], function(tag, id) {
output[id] = tag;
});
utils._each(params, function(param, id) {
output[id] = param;
});
this.tags[tagId] = output;
}
}
describe('Unit: Prebid Module', function () {
let bidExpiryStub;
beforeEach(function () {
bidExpiryStub = sinon.stub(filters, 'isBidNotExpired').callsFake(() => true);
configObj.setConfig({ useBidCache: true });
});
afterEach(function() {
$$PREBID_GLOBAL$$.adUnits = [];
bidExpiryStub.restore();
configObj.setConfig({ useBidCache: false });
});
after(function() {
auctionManager.clearAllAuctions();
});
describe('getAdserverTargetingForAdUnitCodeStr', function () {
beforeEach(function () {
resetAuction();
});
it('should return targeting info as a string', function () {
const adUnitCode = config.adUnitCodes[0];
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
var expected = 'foobar=0x0%2C300x250%2C300x600&' + CONSTANTS.TARGETING_KEYS.SIZE + '=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_triplelift=0x0&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + CONSTANTS.TARGETING_KEYS.SIZE + '_appnexus=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pagescience=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brightcom=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brealtime=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + CONSTANTS.TARGETING_KEYS.SIZE + '_rubicon=300x600&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_rubicon=rubicon';
var result = $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCodeStr(adUnitCode);
assert.equal(expected, result, 'returns expected string of ad targeting info');
});
it('should log message if adunitCode param is falsey', function () {
var spyLogMessage = sinon.spy(utils, 'logMessage');
var result = $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCodeStr();
assert.ok(spyLogMessage.calledWith('Need to call getAdserverTargetingForAdUnitCodeStr with adunitCode'), 'expected message was logged');
assert.equal(result, undefined, 'result is undefined');
utils.logMessage.restore();
});
});
describe('getAdserverTargetingForAdUnitCode', function () {
it('should return targeting info as an object', function () {
const adUnitCode = config.adUnitCodes[0];
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
var result = $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCode(adUnitCode);
const expected = getAdServerTargeting()[adUnitCode];
assert.deepEqual(result, expected, 'returns expected' +
' targeting info object');
});
});
describe('getAdServerTargeting', function () {
beforeEach(function () {
resetAuction();
});
afterEach(function () {
resetAuction();
});
it('should return current targeting data for slots', function () {
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
const targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
const expected = getAdServerTargeting(['/19968336/header-bid-tag-0, /19968336/header-bid-tag1']);
assert.deepEqual(targeting, expected, 'targeting ok');
});
it('should return correct targeting with default settings', function () {
var targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
var expected = {
'/19968336/header-bid-tag-0': {
foobar: '0x0,300x250,300x600',
[CONSTANTS.TARGETING_KEYS.SIZE]: '300x250',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus'
},
'/19968336/header-bid-tag1': {
foobar: '728x90',
[CONSTANTS.TARGETING_KEYS.SIZE]: '728x90',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus'
}
};
assert.deepEqual(targeting, expected);
});
it('should return correct targeting with bid landscape targeting on', function () {
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
var targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
var expected = getAdServerTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
assert.deepEqual(targeting, expected);
});
it("should include a losing bid's custom ad targeting key", function () {
// Let's make sure we're getting the expected losing bid.
assert.equal(auction.getBidsReceived()[0]['bidderCode'], 'triplelift');
assert.equal(auction.getBidsReceived()[0]['cpm'], 0.112256);
// Modify the losing bid to have `alwaysUseBid=true` and a custom `adserverTargeting` key.
let _bidsReceived = getBidResponses();
_bidsReceived[0]['adserverTargeting'] = {
always_use_me: 'abc',
};
auction.getBidsReceived = function() { return _bidsReceived };
var targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
// Ensure targeting for both ad placements includes the custom key.
assert.equal(
targeting['/19968336/header-bid-tag-0'].hasOwnProperty('always_use_me'),
true
);
var expected = {
'/19968336/header-bid-tag-0': {
foobar: '300x250,300x600',
always_use_me: 'abc',
[CONSTANTS.TARGETING_KEYS.SIZE]: '300x250',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus'
},
'/19968336/header-bid-tag1': {
foobar: '728x90',
[CONSTANTS.TARGETING_KEYS.SIZE]: '728x90',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus'
}
};
assert.deepEqual(targeting, expected);
});
it('should not overwrite winning bids custom keys targeting key', function () {
resetAuction();
// mimic a bidderSetting.standard key here for each bid and alwaysUseBid true for every bid
let _bidsReceived = getBidResponses();
_bidsReceived.forEach(bid => {
bid.adserverTargeting.custom_ad_id = bid.adId;
});
auction.getBidsReceived = function() { return _bidsReceived };
$$PREBID_GLOBAL$$.bidderSettings = {
'standard': {
adserverTargeting: [{
key: CONSTANTS.TARGETING_KEYS.BIDDER,
val: function(bidResponse) {
return bidResponse.bidderCode;
}
}, {
key: 'custom_ad_id',
val: function(bidResponse) {
return bidResponse.adId;
}
}, {
key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET,
val: function(bidResponse) {
return bidResponse.pbMg;
}
}, {
key: 'foobar',
val: function(bidResponse) {
return bidResponse.size;
}
}]
}
};
var targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
var expected = {
'/19968336/header-bid-tag-0': {
foobar: '300x250',
custom_ad_id: '233bcbee889d46d',
[CONSTANTS.TARGETING_KEYS.SIZE]: '300x250',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus'
},
'/19968336/header-bid-tag1': {
foobar: '728x90',
[CONSTANTS.TARGETING_KEYS.SIZE]: '728x90',
[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00',
[CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc',
[CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus',
custom_ad_id: '24bd938435ec3fc'
}
};
assert.deepEqual(targeting, expected);
$$PREBID_GLOBAL$$.bidderSettings = {};
});
it('should not send standard targeting keys when the bid has `sendStandardTargeting` set to `false`', function () {
let _bidsReceived = getBidResponses();
_bidsReceived.forEach(bid => {
bid.adserverTargeting.custom_ad_id = bid.adId;
bid.sendStandardTargeting = false;
});
auction.getBidsReceived = function() { return _bidsReceived };
var targeting = $$PREBID_GLOBAL$$.getAdserverTargeting(['/19968336/header-bid-tag-0', '/19968336/header-bid-tag1']);
var expected = {
'/19968336/header-bid-tag-0': {
foobar: '0x0,300x250,300x600',
custom_ad_id: '222bb26f9e8bd,233bcbee889d46d,25bedd4813632d7,26e0795ab963896,275bd666f5a5a5d,28f4039c636b6a7,29019e2ab586a5a'
},
'/19968336/header-bid-tag1': {
foobar: '728x90',
custom_ad_id: '24bd938435ec3fc'
}
};
assert.deepEqual(targeting, expected);
});
});
describe('getAdserverTargeting', function() {
const customConfigObject = {
'buckets': [
{ 'precision': 2, 'max': 5, 'increment': 0.01 },
{ 'precision': 2, 'max': 8, 'increment': 0.05 },
{ 'precision': 2, 'max': 20, 'increment': 0.5 },
{ 'precision': 2, 'max': 25, 'increment': 1 }
]
};
let currentPriceBucket;
let bid;
let auction;
let ajaxStub;
let cbTimeout = 3000;
let targeting;
let RESPONSE = {
'version': '0.0.1',
'tags': [{
'uuid': '4d0a6829338a07',
'tag_id': 4799418,
'auction_id': '2256922143947979797',
'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
'timeout_ms': 2500,
'ads': [{
'content_source': 'rtb',
'ad_type': 'banner',
'buyer_member_id': 958,
'creative_id': 33989846,
'media_type_id': 1,
'media_subtype_id': 1,
'cpm': 1.99,
'cpm_publisher_currency': 0.500000,
'publisher_currency_code': '$',
'client_initiated_ad_counting': true,
'rtb': {
'banner': {
'width': 728,
'height': 90,
'content': '<!-- Creative -->'
},
'trackers': [{
'impression_urls': ['http://lax1-ib.adnxs.com/impression']
}]
},
'viewability': {
'config': '<script type=\'text/javascript\' async=\'true\' src=\'http://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=http%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttp%253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'}
}]
}]
};
before(function () {
$$PREBID_GLOBAL$$.bidderSettings = {};
currentPriceBucket = configObj.getConfig('priceGranularity');
configObj.setConfig({ priceGranularity: customConfigObject });
sinon.stub(adapterManager, 'makeBidRequests').callsFake(() => ([{
'bidderCode': 'appnexus',
'auctionId': '20882439e3238c',
'bidderRequestId': '331f3cf3f1d9c8',
'bids': [
{
'bidder': 'appnexus',
'params': {
'placementId': '10433394'
},
'adUnitCode': 'div-gpt-ad-1460505748561-0',
'sizes': [
[
300,
250
],
[
300,
600
]
],
'bidId': '4d0a6829338a07',
'bidderRequestId': '331f3cf3f1d9c8',
'auctionId': '20882439e3238c'
}
],
'auctionStart': 1505250713622,
'timeout': 3000
}]
));
});
after(function () {
configObj.setConfig({ priceGranularity: currentPriceBucket });
adapterManager.makeBidRequests.restore();
})
beforeEach(function () {
let auctionManagerInstance = newAuctionManager();
targeting = newTargeting(auctionManagerInstance);
let adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
sizes: [[300, 250], [300, 600]],
bids: [{
bidder: 'appnexus',
params: {
placementId: '10433394'
}
}]
}];
let adUnitCodes = ['div-gpt-ad-1460505748561-0'];
auction = auctionManagerInstance.createAuction({adUnits, adUnitCodes});
ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() {
return function(url, callback) {
const fakeResponse = sinon.stub();
fakeResponse.returns('headerContent');
callback.success(JSON.stringify(RESPONSE), { getResponseHeader: fakeResponse });
}
});
});
afterEach(function () {
ajaxStub.restore();
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 0 to 5', function() {
RESPONSE.tags[0].ads[0].cpm = 2.1234;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('2.12');
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 5 to 8', function() {
RESPONSE.tags[0].ads[0].cpm = 6.78;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('6.75');
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 8 to 20', function() {
RESPONSE.tags[0].ads[0].cpm = 19.5234;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('19.50');
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 20 to 25', function() {
RESPONSE.tags[0].ads[0].cpm = 21.5234;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('21.00');
});
});
describe('getAdserverTargeting with `mediaTypePriceGranularity` set for media type', function() {
let currentPriceBucket;
let auction;
let ajaxStub;
let response;
let cbTimeout = 3000;
let auctionManagerInstance;
let targeting;
const bannerResponse = {
'version': '0.0.1',
'tags': [{
'uuid': '4d0a6829338a07',
'tag_id': 4799418,
'auction_id': '2256922143947979797',
'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
'timeout_ms': 2500,
'ads': [{
'content_source': 'rtb',
'ad_type': 'banner',
'buyer_member_id': 958,
'creative_id': 33989846,
'media_type_id': 1,
'media_subtype_id': 1,
'cpm': 1.99,
'cpm_publisher_currency': 0.500000,
'publisher_currency_code': '$',
'client_initiated_ad_counting': true,
'rtb': {
'banner': {
'width': 300,
'height': 250,
'content': '<!-- Creative -->'
},
'trackers': [{
'impression_urls': ['http://lax1-ib.adnxs.com/impression']
}]
},
'viewability': {
'config': '<script type=\'text/javascript\' async=\'true\' src=\'http://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=http%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttp%253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'}
}]
}]
};
const videoResponse = {
'version': '0.0.1',
'tags': [{
'uuid': '4d0a6829338a07',
'tag_id': 4799418,
'auction_id': '2256922143947979797',
'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad',
'timeout_ms': 2500,
'ads': [{
'content_source': 'rtb',
'ad_type': 'video',
'buyer_member_id': 958,
'creative_id': 33989846,
'media_type_id': 1,
'media_subtype_id': 1,
'cpm': 1.99,
'cpm_publisher_currency': 0.500000,
'publisher_currency_code': '$',
'client_initiated_ad_counting': true,
'rtb': {
'video': {
'width': 300,
'height': 250,
'content': '<!-- Creative -->'
},
'trackers': [{
'impression_urls': ['http://lax1-ib.adnxs.com/impression']
}]
},
'viewability': {
'config': '<script type=\'text/javascript\' async=\'true\' src=\'http://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=http%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttp%253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'}
}]
}]
};
const createAdUnit = (code, mediaTypes) => {
if (!mediaTypes) {
mediaTypes = ['banner'];
} else if (typeof mediaTypes === 'string') {
mediaTypes = [mediaTypes];
}
const adUnit = {
code: code,
sizes: [[300, 250], [300, 600]],
bids: [{
bidder: 'appnexus',
params: {
placementId: '10433394'
}
}]
};
let _mediaTypes = {};
if (mediaTypes.indexOf('banner') !== -1) {
_mediaTypes['banner'] = {
'banner': {}
};
}
if (mediaTypes.indexOf('video') !== -1) {
_mediaTypes['video'] = {
'video': {
context: 'instream',
playerSize: [300, 250]
}
};
}
if (mediaTypes.indexOf('native') !== -1) {
_mediaTypes['native'] = {
'native': {}
};
}
if (Object.keys(_mediaTypes).length > 0) {
adUnit['mediaTypes'] = _mediaTypes;
// if video type, add video to every bid.param object
if (_mediaTypes.video) {
adUnit.bids.forEach(bid => {
bid.params['video'] = {
width: 300,
height: 250,
vastUrl: '',
ttl: 3600
};
});
}
}
return adUnit;
}
const initTestConfig = (data) => {
$$PREBID_GLOBAL$$.bidderSettings = {};
ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() {
return function(url, callback) {
const fakeResponse = sinon.stub();
fakeResponse.returns('headerContent');
callback.success(JSON.stringify(response), { getResponseHeader: fakeResponse });
}
});
auctionManagerInstance = newAuctionManager();
targeting = newTargeting(auctionManagerInstance)
configObj.setConfig({
'priceGranularity': {
'buckets': [
{ 'precision': 2, 'max': 5, 'increment': 0.01 },
{ 'precision': 2, 'max': 8, 'increment': 0.05 },
{ 'precision': 2, 'max': 20, 'increment': 0.5 },
{ 'precision': 2, 'max': 25, 'increment': 1 }
]
},
'mediaTypePriceGranularity': {
'banner': {
'buckets': [
{ 'precision': 2, 'max': 5, 'increment': 0.25 },
{ 'precision': 2, 'max': 20, 'increment': 0.5 },
{ 'precision': 2, 'max': 100, 'increment': 1 }
]
},
'video': 'low',
'native': 'high'
}
});
auction = auctionManagerInstance.createAuction({
adUnits: data.adUnits,
adUnitCodes: data.adUnitCodes
});
};
before(function () {
currentPriceBucket = configObj.getConfig('priceGranularity');
sinon.stub(adapterManager, 'makeBidRequests').callsFake(() => ([{
'bidderCode': 'appnexus',
'auctionId': '20882439e3238c',
'bidderRequestId': '331f3cf3f1d9c8',
'bids': [
{
'bidder': 'appnexus',
'params': {
'placementId': '10433394'
},
'adUnitCode': 'div-gpt-ad-1460505748561-0',
'sizes': [
[
300,
250
],
[
300,
600
]
],
'bidId': '4d0a6829338a07',
'bidderRequestId': '331f3cf3f1d9c8',
'auctionId': '20882439e3238c'
}
],
'auctionStart': 1505250713622,
'timeout': 3000
}]));
});
after(function () {
configObj.setConfig({ priceGranularity: currentPriceBucket });
adapterManager.makeBidRequests.restore();
})
afterEach(function () {
ajaxStub.restore();
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 0 - 5', function() {
initTestConfig({
adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
adUnitCodes: ['div-gpt-ad-1460505748561-0']
});
response = bannerResponse;
response.tags[0].ads[0].cpm = 3.4288;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.25');
});
it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 21 - 100', function() {
initTestConfig({
adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')],
adUnitCodes: ['div-gpt-ad-1460505748561-0']
});
response = bannerResponse;
response.tags[0].ads[0].cpm = 43.4288;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('43.00');
});
it('should only apply price granularity if bid media type matches', function () {
initTestConfig({
adUnits: [ createAdUnit('div-gpt-ad-1460505748561-0', 'video') ],
adUnitCodes: ['div-gpt-ad-1460505748561-0']
});
response = videoResponse;
response.tags[0].ads[0].cpm = 3.4288;
auction.callBids(cbTimeout);
let bidTargeting = targeting.getAllTargeting();
expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.00');
});
});
describe('getBidResponses', function () {
it('should return empty obj when last auction Id had no responses', function () {
auctionManager.getLastAuctionId = () => 999994;
var result = $$PREBID_GLOBAL$$.getBidResponses();
assert.deepEqual(result, {}, 'expected bid responses are returned');
});
it('should return expected bid responses when not passed an adunitCode', function () {
auctionManager.getLastAuctionId = () => 654321;
var result = $$PREBID_GLOBAL$$.getBidResponses();
var compare = getBidResponsesFromAPI();
assert.deepEqual(result, compare, 'expected bid responses are returned');
});
it('should return bid responses for most recent auctionId only', function () {
const responses = $$PREBID_GLOBAL$$.getBidResponses();
assert.equal(responses[Object.keys(responses)[0]].bids.length, 4);
});
});
describe('getBidResponsesForAdUnitCode', function () {
it('should return bid responses as expected', function () {
const adUnitCode = '/19968336/header-bid-tag-0';
const result = $$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode);
const bids = getBidResponses().filter(bid => bid.adUnitCode === adUnitCode);
const compare = { bids: bids };
assert.deepEqual(result, compare, 'expected id responses for ad unit code are returned');
});
});
describe('setTargetingForGPTAsync', function () {
let logErrorSpy;
beforeEach(function () {
logErrorSpy = sinon.spy(utils, 'logError');
resetAuction();
});
afterEach(function () {
utils.logError.restore();
resetAuction();
});
it('should set googletag targeting keys after calling setTargetingForGPTAsync function', function () {
var slots = createSlotArrayScenario2();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync([config.adUnitCodes[0]]);
// we need to transform the spySetTargeting into something that looks like
// googletag's targeting structure
// googletag setTargeting will override old value if invoked with same key
const targeting = [];
slots[1].getTargetingKeys().map(function (key) {
const value = slots[1].getTargeting(key);
targeting.push([key, value]);
});
var invokedTargetingMap = {};
slots[1].spySetTargeting.args.map(function (entry) {
invokedTargetingMap[entry[0]] = entry[1];
});
var invokedTargeting = [];
Object.getOwnPropertyNames(invokedTargetingMap).map(function (key) {
const value = Array.isArray(invokedTargetingMap[key]) ? invokedTargetingMap[key] : [invokedTargetingMap[key]]; // values are always returned as array in googletag
invokedTargeting.push([key, value]);
});
assert.deepEqual(targeting, invokedTargeting, 'google tag targeting options not matching');
});
it('should set googletag targeting keys to specific slot with customSlotMatching', function () {
// same ad unit code but two differnt divs
// we make sure we can set targeting for a specific one with customSlotMatching
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: false });
var slots = [
new Slot('div-id-one', config.adUnitCodes[0]),
new Slot('div-id-two', config.adUnitCodes[0]),
new Slot(config.adUnitElementIDs[2], config.adUnitCodes[2])
];
slots[0].spySetTargeting.resetHistory();
slots[1].spySetTargeting.resetHistory();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync([config.adUnitCodes[0]], (slot) => {
return (adUnitCode) => {
return slots[0].getSlotElementId() === slot.getSlotElementId();
};
});
var expected = getTargetingKeys();
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
expect(slots[1].spySetTargeting.args).to.not.deep.contain.members(expected);
});
it('should set targeting when passed a string ad unit code with enableSendAllBids', function () {
var slots = createSlotArray();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
$$PREBID_GLOBAL$$.setTargetingForGPTAsync('/19968336/header-bid-tag-0');
expect(slots[0].spySetTargeting.args).to.deep.contain.members([[CONSTANTS.TARGETING_KEYS.BIDDER, 'appnexus'], [CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]);
});
it('should set targeting when passed an array of ad unit codes with enableSendAllBids', function () {
var slots = createSlotArray();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
$$PREBID_GLOBAL$$.setTargetingForGPTAsync(['/19968336/header-bid-tag-0']);
expect(slots[0].spySetTargeting.args).to.deep.contain.members([[CONSTANTS.TARGETING_KEYS.BIDDER, 'appnexus'], [CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]);
});
it('should set targeting from googletag data', function () {
var slots = createSlotArray();
slots[0].spySetTargeting.resetHistory();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync();
var expected = getTargetingKeys();
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
});
it('should find correct gpt slot based on ad id rather than ad unit code when resizing secure creative', function () {
var slots = [
new Slot('div-not-matching-adunit-code-1', config.adUnitCodes[0]),
new Slot('div-not-matching-adunit-code-2', config.adUnitCodes[0]),
new Slot('div-not-matching-adunit-code-3', config.adUnitCodes[0])
];
slots[1].setTargeting('hb_adid', ['someAdId']);
slots[1].spyGetSlotElementId.resetHistory();
window.googletag.pubads().setSlots(slots);
const mockAdObject = {
adId: 'someAdId',
ad: '<script src="http://prebid.org/creative/${AUCTION_PRICE}"></script>',
adUrl: 'http://creative.prebid.org/${AUCTION_PRICE}',
width: 300,
height: 250,
renderer: null,
cpm: '1.00',
adUnitCode: config.adUnitCodes[0],
};
const event = {
source: { postMessage: sinon.stub() },
origin: 'origin.sf.com'
};
_sendAdToCreative(mockAdObject, event);
expect(slots[0].spyGetSlotElementId.called).to.equal(false);
expect(slots[1].spyGetSlotElementId.called).to.equal(true);
expect(slots[2].spyGetSlotElementId.called).to.equal(false);
});
it('Calling enableSendAllBids should set targeting to include standard keys with bidder' +
' append to key name', function () {
var slots = createSlotArray();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true });
$$PREBID_GLOBAL$$.setTargetingForGPTAsync();
var expected = getTargetingKeysBidLandscape();
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
});
it('should set targeting for bids', function () {
// Make sure we're getting the expected losing bid.
assert.equal(auctionManager.getBidsReceived()[0]['bidderCode'], 'triplelift');
assert.equal(auctionManager.getBidsReceived()[0]['cpm'], 0.112256);
resetAuction();
// Modify the losing bid to have `alwaysUseBid=true` and a custom `adserverTargeting` key.
let _bidsReceived = getBidResponses();
_bidsReceived[0]['adserverTargeting'] = {
always_use_me: 'abc',
};
auction.getBidsReceived = function() { return _bidsReceived };
var slots = createSlotArray();
window.googletag.pubads().setSlots(slots);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync();
var expected = [
[
CONSTANTS.TARGETING_KEYS.BIDDER,
'appnexus'
],
[
CONSTANTS.TARGETING_KEYS.AD_ID,
'233bcbee889d46d'
],
[
CONSTANTS.TARGETING_KEYS.PRICE_BUCKET,
'10.00'
],
[
CONSTANTS.TARGETING_KEYS.SIZE,
'300x250'
],
[
'foobar',
['300x250', '300x600']
],
[
'always_use_me',
'abc'
]
];
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
});
it('should log error when googletag is not defined on page', function () {
const error = 'window.googletag is not defined on the page';
const windowGoogletagBackup = window.googletag;
window.googletag = {};
$$PREBID_GLOBAL$$.setTargetingForGPTAsync();
assert.ok(logErrorSpy.calledWith(error), 'expected error was logged');
window.googletag = windowGoogletagBackup;
});
it('should emit SET_TARGETING event when successfully invoked', function() {
var slots = createSlotArray();
window.googletag.pubads().setSlots(slots);
var callback = sinon.spy();
$$PREBID_GLOBAL$$.onEvent('setTargeting', callback);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync(config.adUnitCodes);
sinon.assert.calledOnce(callback);
});
});
describe('renderAd', function () {
var bidId = 1;
var doc = {};
var elStub = {};
var adResponse = {};
var spyLogError = null;
var spyLogMessage = null;
var spyLogWarn = null;
var spyAddWinningBid;
var inIframe = true;
var triggerPixelStub;
function pushBidResponseToAuction(obj) {
adResponse = Object.assign({
auctionId: 1,
adId: bidId,
width: 300,
height: 250,
}, obj);
auction.getBidsReceived = function() {
let bidsReceived = getBidResponses();
bidsReceived.push(adResponse);
return bidsReceived;
}
auction.getAuctionId = () => 1;
}
beforeEach(function () {
doc = {
write: sinon.spy(),
close: sinon.spy(),
defaultView: {
frameElement: {
width: 0,
height: 0
}
},
getElementsByTagName: sinon.stub()
};
elStub = {
insertBefore: sinon.stub()
};
doc.getElementsByTagName.returns([elStub]);
spyLogError = sinon.spy(utils, 'logError');
spyLogMessage = sinon.spy(utils, 'logMessage');
spyLogWarn = sinon.spy(utils, 'logWarn');
spyAddWinningBid = sinon.spy(auctionManager, 'addWinningBid');
inIframe = true;
sinon.stub(utils, 'inIframe').callsFake(() => inIframe);
triggerPixelStub = sinon.stub(utils.internal, 'triggerPixel');
});
afterEach(function () {
auction.getBidsReceived = getBidResponses;
utils.logError.restore();
utils.logMessage.restore();
utils.logWarn.restore();
utils.inIframe.restore();
triggerPixelStub.restore();
spyAddWinningBid.restore();
});
it('should require doc and id params', function () {
$$PREBID_GLOBAL$$.renderAd();
var error = 'Error trying to write ad Id :undefined to the page. Missing document or adId';
assert.ok(spyLogError.calledWith(error), 'expected param error was logged');
});
it('should log message with bid id', function () {
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
var message = 'Calling renderAd with adId :' + bidId;
assert.ok(spyLogMessage.calledWith(message), 'expected message was logged');
});
it('should write the ad to the doc', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});
adResponse.ad = "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>";
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
assert.ok(doc.write.calledWith(adResponse.ad), 'ad was written to doc');
assert.ok(doc.close.called, 'close method called');
});
it('should place the url inside an iframe on the doc', function () {
pushBidResponseToAuction({
adUrl: 'http://server.example.com/ad/ad.js'
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
assert.ok(elStub.insertBefore.called, 'url was written to iframe in doc');
});
it('should log an error when no ad or url', function () {
pushBidResponseToAuction({});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
var error = 'Error trying to write ad. No ad for bid response id: ' + bidId;
assert.ok(spyLogError.calledWith(error), 'expected error was logged');
});
it('should log an error when not in an iFrame', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});
inIframe = false;
$$PREBID_GLOBAL$$.renderAd(document, bidId);
const error = 'Error trying to write ad. Ad render call ad id ' + bidId + ' was prevented from writing to the main document.';
assert.ok(spyLogError.calledWith(error), 'expected error was logged');
});
it('should not render videos', function () {
pushBidResponseToAuction({
mediatype: 'video'
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
sinon.assert.notCalled(doc.write);
});
it('should catch errors thrown when trying to write ads to the page', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});
var error = { message: 'doc write error' };
doc.write = sinon.stub().throws(error);
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
var errorMessage = 'Error trying to write ad Id :' + bidId + ' to the page:' + error.message;
assert.ok(spyLogError.calledWith(errorMessage), 'expected error was logged');
});
it('should log an error when ad not found', function () {
var fakeId = 99;
$$PREBID_GLOBAL$$.renderAd(doc, fakeId);
var error = 'Error trying to write ad. Cannot find ad by given id : ' + fakeId;
assert.ok(spyLogError.calledWith(error), 'expected error was logged');
});
it('should save bid displayed to winning bid', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
assert.deepEqual($$PREBID_GLOBAL$$.getAllWinningBids()[0], adResponse);
});
it('should replace ${CLICKTHROUGH} macro in winning bids response', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js?clickthrough=${CLICKTHROUGH}'></script>"
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId, {clickThrough: 'https://someadserverclickurl.com'});
expect(adResponse).to.have.property('ad').and.to.match(/https:\/\/someadserverclickurl\.com/i);
});
it('fires billing url if present on s2s bid', function () {
const burl = 'http://www.example.com/burl';
pushBidResponseToAuction({
ad: '<div>ad</div>',
source: 's2s',
burl
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
sinon.assert.calledOnce(triggerPixelStub);
sinon.assert.calledWith(triggerPixelStub, burl);
});
it('should call addWinningBid', function () {
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
var message = 'Calling renderAd with adId :' + bidId;
sinon.assert.calledWith(spyLogMessage, message);
sinon.assert.calledOnce(spyAddWinningBid);
sinon.assert.calledWith(spyAddWinningBid, adResponse);
});
it('should warn stale rendering', function () {
var message = 'Calling renderAd with adId :' + bidId;
var warning = `Ad id ${bidId} has been rendered before`;
var onWonEvent = sinon.stub();
var onStaleEvent = sinon.stub();
$$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.BID_WON, onWonEvent);
$$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.STALE_RENDER, onStaleEvent);
pushBidResponseToAuction({
ad: "<script type='text/javascript' src='http://server.example.com/ad/ad.js'></script>"
});