diff --git a/modules/adagioAnalyticsAdapter.js b/modules/adagioAnalyticsAdapter.js index 9c4c0e8fea7..ee2368fde08 100644 --- a/modules/adagioAnalyticsAdapter.js +++ b/modules/adagioAnalyticsAdapter.js @@ -22,6 +22,12 @@ const cache = { getAuction: function(auctionId, adUnitCode) { return this.auctions[auctionId][adUnitCode]; }, + getBiddersFromAuction: function(auctionId, adUnitCode) { + return this.getAuction(auctionId, adUnitCode).bdrs.split(','); + }, + getAllAdUnitCodes: function(auctionId) { + return Object.keys(this.auctions[auctionId]); + }, updateAuction: function(auctionId, adUnitCode, values) { this.auctions[auctionId][adUnitCode] = { ...this.auctions[auctionId][adUnitCode], @@ -74,7 +80,8 @@ const adagioEnqueue = function adagioEnqueue(action, data) { const guard = { adagio: (value) => isAdagio(value), - bidTracked: (auctionId, adUnitCode) => deepAccess(cache, `auctions.${auctionId}.${adUnitCode}`, false) + bidTracked: (auctionId, adUnitCode) => deepAccess(cache, `auctions.${auctionId}.${adUnitCode}`, false), + auctionTracked: (auctionId) => deepAccess(cache, `auctions.${auctionId}`, false) }; function removeDuplicates(arr, getKey) { @@ -105,6 +112,19 @@ function getMediaTypeAlias(mediaType) { return mediaTypesMap[mediaType] || mediaType; }; +function addKeyPrefix(obj, prefix) { + return Object.keys(obj).reduce((acc, key) => { + // We don't want to prefix already prefixed keys. + if (key.startsWith(prefix)) { + acc[key] = obj[key]; + return acc; + } + + acc[`${prefix}${key}`] = obj[key]; + return acc; + }, {}); +} + /** * sendRequest to Adagio. It filter null values and encode each query param. * @param {Object} qp @@ -146,6 +166,7 @@ function getTargetedAuctionId(bid) { * HANDLERS * - handlerAuctionInit * - handlerBidResponse + * - handlerAuctionEnd * - handlerBidWon * - handlerAdRender * @@ -227,11 +248,10 @@ function handlerAuctionInit(event) { auct_id: adagioAuctionId, adu_code: adUnitCode, url_dmn: w.location.hostname, - dvc: params.environment, pgtyp: params.pagetype, plcmt: params.placement, - tname: params.testName || null, - tvname: params.testVariationName || null, + t_n: params.testName || null, + t_v: params.testVersion || null, mts: mediaTypesKeys.join(','), ban_szs: bannerSizes.join(','), bdrs: bidders.map(bidder => getAdapterNameForAlias(bidder.bidder)).sort().join(','), @@ -257,11 +277,33 @@ function handlerBidResponse(event) { return; } + if (!event.pba) { + return; + } + cache.updateAuction(event.auctionId, event.adUnitCode, { - adg_sid: event.seatId || null + ...addKeyPrefix(event.pba, 'e_') }); }; +function handlerAuctionEnd(event) { + const { auctionId } = event; + + if (!guard.auctionTracked(auctionId)) { + return; + } + + const adUnitCodes = cache.getAllAdUnitCodes(auctionId); + adUnitCodes.forEach(adUnitCode => { + const mapper = (bidder) => event.bidsReceived.find(bid => bid.adUnitCode === adUnitCode && bid.bidder === bidder) ? '1' : '0'; + + cache.updateAuction(auctionId, adUnitCode, { + bdrs_bid: cache.getBiddersFromAuction(auctionId, adUnitCode).map(mapper).join(',') + }); + sendNewBeacon(auctionId, adUnitCode); + }); +} + function handlerBidWon(event) { let auctionId = getTargetedAuctionId(event); @@ -340,10 +382,14 @@ let adagioAdapter = Object.assign(adapter({ emptyUrl, analyticsType }), { case CONSTANTS.EVENTS.BID_RESPONSE: handlerBidResponse(args); break; + case CONSTANTS.EVENTS.AUCTION_END: + handlerAuctionEnd(args); + break; case CONSTANTS.EVENTS.BID_WON: handlerBidWon(args); break; - case CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED: + // AD_RENDER_SUCCEEDED seems redundant with BID_WON. + // case CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED: case CONSTANTS.EVENTS.AD_RENDER_FAILED: handlerAdRender(args, eventType === CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED); break; diff --git a/test/spec/modules/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index 8359a34baa0..5ffd7b0b685 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -211,7 +211,10 @@ const BID_ADAGIO = Object.assign({}, BID_ADAGIO, { meta: { advertiserDomains: ['example.com'] }, - seatId: '42', + pba: { + sid: '42', + e_pba_test: true + } }); const BID_ANOTHER = Object.assign({}, BID_ANOTHER, { @@ -256,7 +259,9 @@ const PARAMS_ADG = { pageviewId: 'a68e6d70-213b-496c-be0a-c468ff387106', environment: 'desktop', pagetype: 'article', - placement: 'pave_top' + placement: 'pave_top', + testName: 'test', + testVersion: 'version', }; const AUCTION_INIT_ANOTHER = { @@ -285,6 +290,11 @@ const AUCTION_INIT_ANOTHER = { 'params': { 'publisherId': '1001' }, + }, { + 'bidder': 'nobid', + 'params': { + 'publisherId': '1002' + }, }, { 'bidder': 'adagio', 'params': { @@ -354,6 +364,24 @@ const AUCTION_INIT_ANOTHER = { 'auctionId': AUCTION_ID, 'src': 'client', 'bidRequestsCount': 1 + }, { + 'bidder': 'nobid', + 'params': { + 'publisherId': '1001' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480]] + } + }, + 'adUnitCode': '/19968336/footer-bid-tag-1', + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'sizes': [[640, 480]], + 'bidId': '2ecff0db240757', + 'bidderRequestId': '1be65d7958826a', + 'auctionId': AUCTION_ID, + 'src': 'client', + 'bidRequestsCount': 1 } ], 'timeout': 3000, @@ -533,6 +561,14 @@ const AUCTION_INIT_CACHE = { 'timeout': 3000 }; +const AUCTION_END_ANOTHER = Object.assign({}, AUCTION_INIT_ANOTHER, { + bidsReceived: [BID_ANOTHER, BID_ADAGIO] +}); + +const AUCTION_END_ANOTHER_NOBID = Object.assign({}, AUCTION_INIT_ANOTHER, { + bidsReceived: [] +}); + const MOCK = { SET_TARGETING: { [BID_ADAGIO.adUnitCode]: BID_ADAGIO.adserverTargeting, @@ -546,6 +582,10 @@ const MOCK = { adagio: BID_ADAGIO, another: BID_ANOTHER }, + AUCTION_END: { + another: AUCTION_END_ANOTHER, + another_nobid: AUCTION_END_ANOTHER_NOBID + }, BID_WON: { adagio: Object.assign({}, BID_ADAGIO, { 'status': 'rendered' @@ -569,6 +609,12 @@ const MOCK = { bid: BID_CACHED } }, + AD_RENDER_FAILED: { + bidcached: { + adId: 'fake_ad_id_2', + bid: BID_CACHED + } + } }; describe('adagio analytics adapter', () => { @@ -616,10 +662,11 @@ describe('adagio analytics adapter', () => { events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END.another); events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON.another); events.emit(constants.EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); - expect(server.requests.length).to.equal(3); + expect(server.requests.length).to.equal(3, 'requests count'); { const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[0].url); expect(protocol).to.equal('https'); @@ -633,12 +680,11 @@ describe('adagio analytics adapter', () => { expect(search.site).to.equal('test-com'); expect(search.pv_id).to.equal('a68e6d70-213b-496c-be0a-c468ff387106'); expect(search.url_dmn).to.equal(window.location.hostname); - expect(search.dvc).to.equal('desktop'); expect(search.pgtyp).to.equal('article'); expect(search.plcmt).to.equal('pave_top'); expect(search.mts).to.equal('ban'); expect(search.ban_szs).to.equal('640x100,640x480'); - expect(search.bdrs).to.equal('adagio,another'); + expect(search.bdrs).to.equal('adagio,another,nobid'); expect(search.adg_mts).to.equal('ban'); } @@ -648,9 +694,19 @@ describe('adagio analytics adapter', () => { expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); expect(search.v).to.equal('2'); + expect(search.e_sid).to.equal('42'); + expect(search.e_pba_test).to.equal('true'); + expect(search.bdrs_bid).to.equal('1,1,0'); + } + + { + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[2].url); + expect(protocol).to.equal('https'); + expect(hostname).to.equal('c.4dex.io'); + expect(pathname).to.equal('/pba.gif'); + expect(search.v).to.equal('3'); expect(search.auct_id).to.equal(AUCTION_ID_ADAGIO); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); - expect(search.adg_sid).to.equal('42'); expect(search.win_bdr).to.equal('another'); expect(search.win_mt).to.equal('ban'); expect(search.win_ban_sz).to.equal('728x90'); @@ -661,17 +717,6 @@ describe('adagio analytics adapter', () => { expect(search.og_cur).to.equal('GBP'); expect(search.og_cur_rate).to.equal('1.6'); } - - { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[2].url); - expect(protocol).to.equal('https'); - expect(hostname).to.equal('c.4dex.io'); - expect(pathname).to.equal('/pba.gif'); - expect(search.v).to.equal('3'); - expect(search.auct_id).to.equal(AUCTION_ID_ADAGIO); - expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); - expect(search.rndr).to.equal('1'); - } }); it('builds and sends auction data with a cached bid win', () => { @@ -691,10 +736,11 @@ describe('adagio analytics adapter', () => { events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END.another_nobid); events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON.bidcached); - events.emit(constants.EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.bidcached); + events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED.bidcached); - expect(server.requests.length).to.equal(4); + expect(server.requests.length).to.equal(5, 'requests count'); { const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[0].url); expect(protocol).to.equal('https'); @@ -708,13 +754,14 @@ describe('adagio analytics adapter', () => { expect(search.site).to.equal('test-com'); expect(search.pv_id).to.equal('a68e6d70-213b-496c-be0a-c468ff387106'); expect(search.url_dmn).to.equal(window.location.hostname); - expect(search.dvc).to.equal('desktop'); expect(search.pgtyp).to.equal('article'); expect(search.plcmt).to.equal('pave_top'); expect(search.mts).to.equal('ban'); expect(search.ban_szs).to.equal('640x100,640x480'); expect(search.bdrs).to.equal('adagio,another'); expect(search.adg_mts).to.equal('ban'); + expect(search.t_n).to.equal('test'); + expect(search.t_v).to.equal('version'); } { @@ -730,12 +777,11 @@ describe('adagio analytics adapter', () => { expect(search.site).to.equal('test-com'); expect(search.pv_id).to.equal('a68e6d70-213b-496c-be0a-c468ff387106'); expect(search.url_dmn).to.equal(window.location.hostname); - expect(search.dvc).to.equal('desktop'); expect(search.pgtyp).to.equal('article'); expect(search.plcmt).to.equal('pave_top'); expect(search.mts).to.equal('ban'); expect(search.ban_szs).to.equal('640x100,640x480'); - expect(search.bdrs).to.equal('adagio,another'); + expect(search.bdrs).to.equal('adagio,another,nobid'); expect(search.adg_mts).to.equal('ban'); } @@ -745,10 +791,20 @@ describe('adagio analytics adapter', () => { expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); expect(search.v).to.equal('2'); + expect(search.e_sid).to.equal('42'); + expect(search.e_pba_test).to.equal('true'); + expect(search.bdrs_bid).to.equal('0,0,0'); + } + + { + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[3].url); + expect(protocol).to.equal('https'); + expect(hostname).to.equal('c.4dex.io'); + expect(pathname).to.equal('/pba.gif'); + expect(search.v).to.equal('3'); expect(search.auct_id).to.equal(AUCTION_ID_ADAGIO); expect(search.auct_id_c).to.equal(AUCTION_ID_CACHE_ADAGIO); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); - expect(search.adg_sid).to.equal('42'); expect(search.win_bdr).to.equal('adagio'); expect(search.win_mt).to.equal('ban'); expect(search.win_ban_sz).to.equal('728x90'); @@ -758,18 +814,19 @@ describe('adagio analytics adapter', () => { expect(search.og_cpm).to.equal('1.42'); expect(search.og_cur).to.equal('USD'); expect(search.og_cur_rate).to.equal('1'); + expect(search.rndr).to.not.exist; } { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[3].url); + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[4].url); expect(protocol).to.equal('https'); expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); - expect(search.v).to.equal('3'); + expect(search.v).to.equal('4'); expect(search.auct_id).to.equal(AUCTION_ID_ADAGIO); expect(search.auct_id_c).to.equal(AUCTION_ID_CACHE_ADAGIO); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); - expect(search.rndr).to.equal('1'); + expect(search.rndr).to.equal('0'); } }); });