UNPKG

mk9-prebid

Version:

Header Bidding Management Library

1,257 lines (1,095 loc) 116 kB
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>" });