From 868d524f1783c7b7884845ae6b321e045bbd8322 Mon Sep 17 00:00:00 2001 From: wiem Date: Tue, 30 Aug 2022 14:59:35 +0200 Subject: [PATCH 01/17] start work --- modules/liveintentAnalyticsAdapter.js | 74 +++++++++++++++++++++++++++ modules/liveintentAnalyticsAdapter.md | 9 ++++ 2 files changed, 83 insertions(+) create mode 100644 modules/liveintentAnalyticsAdapter.js create mode 100644 modules/liveintentAnalyticsAdapter.md diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js new file mode 100644 index 00000000000..8dab06827bf --- /dev/null +++ b/modules/liveintentAnalyticsAdapter.js @@ -0,0 +1,74 @@ +import {ajax} from '../src/ajax.js'; +import { deepClone, logInfo, logError } from '../src/utils.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import CONSTANTS from '../src/constants.json'; +import adaptermanager from '../src/adaptermanager.js'; + +const analyticsType = 'endpoint'; +const url = 'https://wba.liadm.com/analytic-events'; +const gvlid = 148; +const adapterCode = 'liAnalytics'; +const bidWonTimeout = 2000; // TODO check +const { EVENTS: { AUCTION_END } } = CONSTANTS; +const payload = {} + +function handleAuctionEnd(args) { + + setTimeout(() => { + let winningBids = $$PREBID_GLOBAL$$.getAllWinningBids(); // wait/get winning bids + // filter winningBids? + let data = createAnalyticsEvent(args, winningBids); // transform data + sendAnalyticsEvent(data); // send data + }, bidWonTimeout); + + + +} + +function createAnalyticsEvent(args, winningBids) { + // generate instanceId + // url ?? is it config.publisherDomain? + +} + +function sendAnalyticsEvent(data) { + ajax(url, { + success: function () { + logInfo('LiveIntent Prebid Analytics: send data success'); + }, + error: function (e) { + logInfo('LiveIntent Prebid Analytics: send data error' + e); + } + }, data, { + contentType: 'application/json', + method: 'POST' + }) +} + +let liAnalytics = Object.assign(adapter({url, analyticsType}), { + track({ eventType, args }) { + if (typeof args !== 'undefined') { + switch (eventType) { + case AUCTION_END: handleAuctionEnd(args); + default: break; + } + } + } +}); + +// save the base class function +liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; + +// override enableAnalytics so we can get access to the config passed in from the page +liAnalytics.enableAnalytics = function (config) { + initOptions = config.options; + liAnalytics.originEnableAnalytics(config); // call the base class function +}; + +adaptermanager.registerAnalyticsAdapter({ + adapter: liAnalytics, + code: adapterCode, + gvlid: gvlid +}); + +export default liAnalytics; diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveintentAnalyticsAdapter.md new file mode 100644 index 00000000000..91a8e1b563e --- /dev/null +++ b/modules/liveintentAnalyticsAdapter.md @@ -0,0 +1,9 @@ +# Overview + +Module Name: LiveIntent Analytics Adapter +Module Type: Analytics Adapter +Maintainer: prebid@example.com + +# Description + +Analytics adapter for Example.com. Contact prebid@example.com for information. Provided by LiveIntent From d826934ad059ed1d5cf33690d6c39f5574964b4f Mon Sep 17 00:00:00 2001 From: wiem Date: Tue, 30 Aug 2022 18:09:38 +0200 Subject: [PATCH 02/17] send analytics event --- modules/liveintentAnalyticsAdapter.js | 64 +++++++++++++++++++++++---- package-lock.json | 23 +++++++++- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 8dab06827bf..7529d223d92 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -1,5 +1,5 @@ import {ajax} from '../src/ajax.js'; -import { deepClone, logInfo, logError } from '../src/utils.js'; +import { generateUUID, logInfo } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; import adaptermanager from '../src/adaptermanager.js'; @@ -13,22 +13,66 @@ const { EVENTS: { AUCTION_END } } = CONSTANTS; const payload = {} function handleAuctionEnd(args) { - setTimeout(() => { let winningBids = $$PREBID_GLOBAL$$.getAllWinningBids(); // wait/get winning bids // filter winningBids? let data = createAnalyticsEvent(args, winningBids); // transform data - sendAnalyticsEvent(data); // send data + sendAnalyticsEvent(data); // send data }, bidWonTimeout); +} +function getAnalyticsEventBids(bidsReceived) { + bidsReceived.map(bid => { + return { + adUnitCode: bid.adUnitCode, + timeToRespond: bid.timeToRespond, + cpm: bid.cpm, + currency: bid.currency, + ttl: bid.ttl, + bidder: bid.bidder + }; + }); +} - +function getBannerSizes(banner) { + banner.sizes.map(size => { + const [width, height] = size + return {w: width, h: height} + }); } function createAnalyticsEvent(args, winningBids) { - // generate instanceId - // url ?? is it config.publisherDomain? + payload['instanceId'] = generateUUID(); + payload['url'] = window.location.protocol + '//' + window.location.hostname + '/'; + payload['bidsReceived'] = getAnalyticsEventBids(args.bidsReceived); + + payload['auctionStart'] = (args.bidderRequests && args.bidderRequests[0]) ? args.bidderRequests[0].auctionStart : 0; + payload['auctionEnd'] = args.auctionEnd; + + payload['adUnits'] = [] + payload['userIds'] = [] + payload['bidders'] = [] + + args.adUnits.forEach(unit => { + if (unit.mediaType && unit.mediaType.banner) { + payload['adUnits'].push({ + code: unit.code, + mediaType: 'banner', + sizes: getBannerSizes(unit.mediaType.banner), + ortb2Imp: unit.ortb2Imp + }) + } + payload['userIds'].push(unit.bids.userIdAsEids) + payload['bidders'].concat(unit.bids.map(bid => { + return { + bidder: bid.bidder, + params: bid.params + }; + })) + }) + payload['winningBids'] = getAnalyticsEventBids(winningBids); + payload['auctionId'] = args.auctionId } function sendAnalyticsEvent(data) { @@ -49,7 +93,9 @@ let liAnalytics = Object.assign(adapter({url, analyticsType}), { track({ eventType, args }) { if (typeof args !== 'undefined') { switch (eventType) { - case AUCTION_END: handleAuctionEnd(args); + case AUCTION_END: + handleAuctionEnd(args); + break; default: break; } } @@ -61,8 +107,8 @@ liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; // override enableAnalytics so we can get access to the config passed in from the page liAnalytics.enableAnalytics = function (config) { - initOptions = config.options; - liAnalytics.originEnableAnalytics(config); // call the base class function +// initOptions = config.options; + liAnalytics.originEnableAnalytics(config); // call the base class function }; adaptermanager.registerAnalyticsAdapter({ diff --git a/package-lock.json b/package-lock.json index 160f2fbfe5f..c0636d3f48e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.10.0-pre", + "version": "7.13.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -21930,6 +21930,20 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "node_modules/typescript": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", + "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -40826,6 +40840,13 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", + "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "dev": true, + "peer": true + }, "typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", From bf710bfb27c0de95ec0b96926ed618e94ed06850 Mon Sep 17 00:00:00 2001 From: leonelcuevas Date: Wed, 31 Aug 2022 15:01:53 +0200 Subject: [PATCH 03/17] Add first test and get winning bids from auctionManager --- modules/liveintentAnalyticsAdapter.js | 70 ++++++++++++------- .../liveIntentAnalyticsAdapter_spec.js | 24 +++++++ 2 files changed, 68 insertions(+), 26 deletions(-) create mode 100644 test/spec/modules/liveIntentAnalyticsAdapter_spec.js diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 7529d223d92..31f03f1ccd2 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -3,6 +3,7 @@ import { generateUUID, logInfo } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; import adaptermanager from '../src/adaptermanager.js'; +import { auctionManager } from '../src/auctionManager.js'; const analyticsType = 'endpoint'; const url = 'https://wba.liadm.com/analytic-events'; @@ -14,15 +15,16 @@ const payload = {} function handleAuctionEnd(args) { setTimeout(() => { - let winningBids = $$PREBID_GLOBAL$$.getAllWinningBids(); // wait/get winning bids - // filter winningBids? - let data = createAnalyticsEvent(args, winningBids); // transform data - sendAnalyticsEvent(data); // send data + let auction = auctionManager.index.getAuction(args.auctionId); + let winningBids = (auction)? auction.getWinningBids() : []; + // sampling? + let data = createAnalyticsEvent(args, winningBids); + sendAnalyticsEvent(data); }, bidWonTimeout); } function getAnalyticsEventBids(bidsReceived) { - bidsReceived.map(bid => { + return bidsReceived.map(bid => { return { adUnitCode: bid.adUnitCode, timeToRespond: bid.timeToRespond, @@ -34,24 +36,24 @@ function getAnalyticsEventBids(bidsReceived) { }); } -function getBannerSizes(banner) { - banner.sizes.map(size => { - const [width, height] = size - return {w: width, h: height} +export function getBannerSizes(banner) { + return banner.sizes.map(size => { + const [width, height] = size; + return {w: width, h: height}; }); } -function createAnalyticsEvent(args, winningBids) { +export function createAnalyticsEvent(args, winningBids) { payload['instanceId'] = generateUUID(); - payload['url'] = window.location.protocol + '//' + window.location.hostname + '/'; + payload['url'] = window.location.protocol + '//' + window.location.hostname + '/'; // window.location.href??? payload['bidsReceived'] = getAnalyticsEventBids(args.bidsReceived); - payload['auctionStart'] = (args.bidderRequests && args.bidderRequests[0]) ? args.bidderRequests[0].auctionStart : 0; + payload['auctionStart'] = (args.bidderRequests && args.bidderRequests[0]) ? args.bidderRequests[0].auctionStart : 0; // make it optional, now, auctionEnd, timestamp??? payload['auctionEnd'] = args.auctionEnd; - payload['adUnits'] = [] - payload['userIds'] = [] - payload['bidders'] = [] + payload['adUnits'] = []; + payload['userIds'] = []; + payload['bidders'] = []; args.adUnits.forEach(unit => { if (unit.mediaType && unit.mediaType.banner) { @@ -60,19 +62,35 @@ function createAnalyticsEvent(args, winningBids) { mediaType: 'banner', sizes: getBannerSizes(unit.mediaType.banner), ortb2Imp: unit.ortb2Imp - }) + }); } - payload['userIds'].push(unit.bids.userIdAsEids) - payload['bidders'].concat(unit.bids.map(bid => { - return { - bidder: bid.bidder, - params: bid.params - }; - })) + + let userIds = unit.bids.flatMap(getUserIds); //remove duplicates???? + payload['userIds'].push(...userIds); + + let bidders = unit.bids.map(getBidder); + payload['bidders'].push(...bidders); }) payload['winningBids'] = getAnalyticsEventBids(winningBids); - payload['auctionId'] = args.auctionId + payload['auctionId'] = args.auctionId; +} + +function getBidder(bid) { + return { + bidder: bid.bidder, + params: bid.params + }; +} + +function getUserIds(bid) { + return bid.userIdAsEids.map(userId => { + return { + source: userId.source, + uids: userId.uids, + ext: userId.ext + }; + }); } function sendAnalyticsEvent(data) { @@ -83,7 +101,7 @@ function sendAnalyticsEvent(data) { error: function (e) { logInfo('LiveIntent Prebid Analytics: send data error' + e); } - }, data, { + }, JSON.stringify(data), { contentType: 'application/json', method: 'POST' }) @@ -107,7 +125,7 @@ liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; // override enableAnalytics so we can get access to the config passed in from the page liAnalytics.enableAnalytics = function (config) { -// initOptions = config.options; + // initOptions = config.options; liAnalytics.originEnableAnalytics(config); // call the base class function }; diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..5783e0920f1 --- /dev/null +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -0,0 +1,24 @@ +import { getBannerSizes, createAnalyticsEvent } from '../../../modules/liveintentAnalyticsAdapter'; +import { expect } from 'chai'; + +describe('LiveIntent Analytics Adapter ', () => { + it('extract sizes', function () { + let expectedResult = [{ + w: 100, + h: 50 + }]; + let banner = { + sizes: [ + [100, 50] + ] + }; + expect(getBannerSizes(banner)).to.deep.equal(expectedResult); + }); + + it('creates analytics event from args and winning bids', () => { + let args = {}; + let winningBids = []; + let expectedResult = {}; + expect(createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); + }); +}); From 4f6254c3d87d90ddd52b772b86fc876773af9f20 Mon Sep 17 00:00:00 2001 From: leonelcuevas Date: Wed, 31 Aug 2022 16:17:09 +0200 Subject: [PATCH 04/17] Add event test data and fix bugs --- modules/liveintentAnalyticsAdapter.js | 35 ++- .../liveIntentAnalyticsAdapter_spec.js | 229 +++++++++++++++++- 2 files changed, 249 insertions(+), 15 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 31f03f1ccd2..eba46b3dc14 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -11,12 +11,11 @@ const gvlid = 148; const adapterCode = 'liAnalytics'; const bidWonTimeout = 2000; // TODO check const { EVENTS: { AUCTION_END } } = CONSTANTS; -const payload = {} function handleAuctionEnd(args) { setTimeout(() => { let auction = auctionManager.index.getAuction(args.auctionId); - let winningBids = (auction)? auction.getWinningBids() : []; + let winningBids = (auction) ? auction.getWinningBids() : []; // sampling? let data = createAnalyticsEvent(args, winningBids); sendAnalyticsEvent(data); @@ -44,11 +43,14 @@ export function getBannerSizes(banner) { } export function createAnalyticsEvent(args, winningBids) { + let payload = {} + let allUserIds = []; + payload['instanceId'] = generateUUID(); - payload['url'] = window.location.protocol + '//' + window.location.hostname + '/'; // window.location.href??? + payload['url'] = window.location.href; payload['bidsReceived'] = getAnalyticsEventBids(args.bidsReceived); - payload['auctionStart'] = (args.bidderRequests && args.bidderRequests[0]) ? args.bidderRequests[0].auctionStart : 0; // make it optional, now, auctionEnd, timestamp??? + payload['auctionStart'] = args.timestamp; payload['auctionEnd'] = args.auctionEnd; payload['adUnits'] = []; @@ -56,24 +58,27 @@ export function createAnalyticsEvent(args, winningBids) { payload['bidders'] = []; args.adUnits.forEach(unit => { - if (unit.mediaType && unit.mediaType.banner) { + if (unit.mediaTypes && unit.mediaTypes.banner) { payload['adUnits'].push({ code: unit.code, mediaType: 'banner', - sizes: getBannerSizes(unit.mediaType.banner), + sizes: getBannerSizes(unit.mediaTypes.banner), ortb2Imp: unit.ortb2Imp }); } - let userIds = unit.bids.flatMap(getUserIds); //remove duplicates???? - payload['userIds'].push(...userIds); - + let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); + allUserIds.push(...userIds); + let bidders = unit.bids.map(getBidder); payload['bidders'].push(...bidders); }) + let uniqueUserIds = allUserIds // TODO remove duplicates???? + payload['userIds'] = uniqueUserIds payload['winningBids'] = getAnalyticsEventBids(winningBids); payload['auctionId'] = args.auctionId; + return payload; } function getBidder(bid) { @@ -83,14 +88,15 @@ function getBidder(bid) { }; } -function getUserIds(bid) { +function getAnalyticsEventUserIds(bid) { return bid.userIdAsEids.map(userId => { - return { + let analyticsEventUserId = { source: userId.source, uids: userId.uids, ext: userId.ext }; - }); + return ignoreUndefined(analyticsEventUserId) + }); } function sendAnalyticsEvent(data) { @@ -107,6 +113,11 @@ function sendAnalyticsEvent(data) { }) } +function ignoreUndefined(data) { + const filteredData = Object.entries(data).filter(([key, value]) => value) + return Object.fromEntries(filteredData) +} + let liAnalytics = Object.assign(adapter({url, analyticsType}), { track({ eventType, args }) { if (typeof args !== 'undefined') { diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index 5783e0920f1..49d07f504f9 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -1,6 +1,131 @@ import { getBannerSizes, createAnalyticsEvent } from '../../../modules/liveintentAnalyticsAdapter'; import { expect } from 'chai'; +let args = { + auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', + timestamp: 1660915379703, + auctionEnd: 1660915381635, + adUnits: [ + { + code: 'ID_Bot100AdJ1', + mediaTypes: { + banner: { + sizes: [ + [ + 300, + 250 + ], + [ + 320, + 50 + ] + ] + } + }, + ortb2Imp: { + ext: { + data: { + adserver: { + name: 'gam', + adslot: '/777/test/home/ID_Bot100AdJ1' + }, + pbadslot: '/777/test/home/ID_Bot100AdJ1' + }, + gpid: '/777/test/home/ID_Bot100AdJ1' + } + }, + bids: [ + { + bidder: 'testBidder', + params: { + siteId: 321218, + zoneId: 1732558, + position: 'bug', + accountId: 10777 + }, + userIdAsEids: [ + { + source: 'source1.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + }, + { + source: 'source2.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + } + ] + }, + { + bidder: 'testBidder2', + params: { + adSlot: '2926251', + publisherId: '159423' + }, + userIdAsEids: [ + { + source: 'source1.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + } + ] + } + ] + } + ], + bidderRequests: [ + { + auctionStart: 1660915379703 + }, + { + auctionStart: 1660915379703 + } + ], + bidsReceived: [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } + ], + winningBids: [] +} + +let winningBids = [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } +]; + describe('LiveIntent Analytics Adapter ', () => { it('extract sizes', function () { let expectedResult = [{ @@ -16,9 +141,107 @@ describe('LiveIntent Analytics Adapter ', () => { }); it('creates analytics event from args and winning bids', () => { - let args = {}; - let winningBids = []; - let expectedResult = {}; + let expectedResult = { + instanceId: '77abbc81-c1f1-41cd-8f25-f7149244c800', + url: 'https://test.com/', + bidsReceived: [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } + ], + auctionStart: 1660915379703, + auctionEnd: 1660915381635, + adUnits: [ + { + code: 'ID_Bot100AdJ1', + mediaType: 'banner', + sizes: [ + { + w: 300, + h: 250 + }, + { + w: 320, + h: 50 + } + ], + ortb2Imp: { + gpid: '/777/test/home/ID_Bot100AdJ1', + ext: { + data: { + aupName: '/777/test/home/ID_Bot100AdJ1', + adserver: { + name: 'gam', + adslot: '/777/test/home/ID_Bot100AdJ1' + }, + pbadslot: '/777/test/home/ID_Bot100AdJ1' + }, + gpid: '/777/test/home/ID_Bot100AdJ1' + } + } + } + ], + winningBids: [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } + ], + auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', + userIds: [ + { + source: 'source1.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + }, + { + source: 'source2.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + } + ], + bidders: [ + { + bidder: 'testBidder', + params: { + siteId: 321218, + zoneId: 1732558, + position: 'bug', + accountId: 10777 + } + }, + { + bidder: 'testBidder2', + params: { + adSlot: '2926251', + publisherId: '159423' + } + } + ] + }; expect(createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); }); }); From 8d681d4435a7de4e0b2b9af8d86379d5c9280933 Mon Sep 17 00:00:00 2001 From: leonelcuevas Date: Thu, 1 Sep 2022 10:17:27 +0200 Subject: [PATCH 05/17] Remove duplicate userIds --- modules/liveintentAnalyticsAdapter.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index eba46b3dc14..058ab6c0611 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -42,6 +42,10 @@ export function getBannerSizes(banner) { }); } +function getUniqueBy(arr, key) { + return [...new Map(arr.map(item => [item[key], item])).values()] +} + export function createAnalyticsEvent(args, winningBids) { let payload = {} let allUserIds = []; @@ -67,14 +71,14 @@ export function createAnalyticsEvent(args, winningBids) { }); } - let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); + let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); allUserIds.push(...userIds); let bidders = unit.bids.map(getBidder); payload['bidders'].push(...bidders); }) - let uniqueUserIds = allUserIds // TODO remove duplicates???? + let uniqueUserIds = getUniqueBy(allUserIds, 'source') // TODO remove duplicates???? payload['userIds'] = uniqueUserIds payload['winningBids'] = getAnalyticsEventBids(winningBids); payload['auctionId'] = args.auctionId; From 7de4175b595b76ec77211f4a3c662db2311e157d Mon Sep 17 00:00:00 2001 From: wiem Date: Thu, 1 Sep 2022 11:05:21 +0200 Subject: [PATCH 06/17] add bidWonTimeout in configOptions --- modules/liveintentAnalyticsAdapter.js | 41 ++++++++++--------- modules/liveintentAnalyticsAdapter.md | 11 +++++ .../liveIntentAnalyticsAdapter_spec.js | 6 +-- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 058ab6c0611..06b52074722 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -8,16 +8,30 @@ import { auctionManager } from '../src/auctionManager.js'; const analyticsType = 'endpoint'; const url = 'https://wba.liadm.com/analytic-events'; const gvlid = 148; -const adapterCode = 'liAnalytics'; -const bidWonTimeout = 2000; // TODO check +const adapterCode = 'liveintent'; const { EVENTS: { AUCTION_END } } = CONSTANTS; +let initOptions = {} + +let liAnalytics = Object.assign(adapter({url, analyticsType}), { + track({ eventType, args }) { + if (typeof args !== 'undefined') { + switch (eventType) { + case AUCTION_END: + handleAuctionEnd(args); + break; + default: break; + } + } + } +}); function handleAuctionEnd(args) { + const bidWonTimeout = initOptions.bidWonTimeout || 2000; setTimeout(() => { let auction = auctionManager.index.getAuction(args.auctionId); let winningBids = (auction) ? auction.getWinningBids() : []; // sampling? - let data = createAnalyticsEvent(args, winningBids); + let data = liAnalytics.createAnalyticsEvent(args, winningBids); sendAnalyticsEvent(data); }, bidWonTimeout); } @@ -35,7 +49,7 @@ function getAnalyticsEventBids(bidsReceived) { }); } -export function getBannerSizes(banner) { +liAnalytics.getBannerSizes = function(banner) { return banner.sizes.map(size => { const [width, height] = size; return {w: width, h: height}; @@ -46,7 +60,7 @@ function getUniqueBy(arr, key) { return [...new Map(arr.map(item => [item[key], item])).values()] } -export function createAnalyticsEvent(args, winningBids) { +liAnalytics.createAnalyticsEvent = function(args, winningBids) { let payload = {} let allUserIds = []; @@ -66,7 +80,7 @@ export function createAnalyticsEvent(args, winningBids) { payload['adUnits'].push({ code: unit.code, mediaType: 'banner', - sizes: getBannerSizes(unit.mediaTypes.banner), + sizes: liAnalytics.getBannerSizes(unit.mediaTypes.banner), ortb2Imp: unit.ortb2Imp }); } @@ -122,25 +136,12 @@ function ignoreUndefined(data) { return Object.fromEntries(filteredData) } -let liAnalytics = Object.assign(adapter({url, analyticsType}), { - track({ eventType, args }) { - if (typeof args !== 'undefined') { - switch (eventType) { - case AUCTION_END: - handleAuctionEnd(args); - break; - default: break; - } - } - } -}); - // save the base class function liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; // override enableAnalytics so we can get access to the config passed in from the page liAnalytics.enableAnalytics = function (config) { - // initOptions = config.options; + initOptions = config.options; liAnalytics.originEnableAnalytics(config); // call the base class function }; diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveintentAnalyticsAdapter.md index 91a8e1b563e..f0da8aefc1f 100644 --- a/modules/liveintentAnalyticsAdapter.md +++ b/modules/liveintentAnalyticsAdapter.md @@ -7,3 +7,14 @@ Maintainer: prebid@example.com # Description Analytics adapter for Example.com. Contact prebid@example.com for information. Provided by LiveIntent + +# Test Parameters + +``` +{ + provider: 'liveintent', + options: { + bidWonTimeout: 2000 + } +} +``` diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index 49d07f504f9..a24d5798034 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import { getBannerSizes, createAnalyticsEvent } from '../../../modules/liveintentAnalyticsAdapter'; +import liAnalytics from '../../../modules/liveintentAnalyticsAdapter'; import { expect } from 'chai'; let args = { @@ -137,7 +137,7 @@ describe('LiveIntent Analytics Adapter ', () => { [100, 50] ] }; - expect(getBannerSizes(banner)).to.deep.equal(expectedResult); + expect(liAnalytics.getBannerSizes(banner)).to.deep.equal(expectedResult); }); it('creates analytics event from args and winning bids', () => { @@ -242,6 +242,6 @@ describe('LiveIntent Analytics Adapter ', () => { } ] }; - expect(createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); + expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); }); }); From 8e04b61121d1f5c7d122d9dbd68ce25bcf488fdc Mon Sep 17 00:00:00 2001 From: wiem Date: Thu, 1 Sep 2022 13:26:28 +0200 Subject: [PATCH 07/17] add sampling and adjust test --- modules/liveintentAnalyticsAdapter.js | 25 ++++++------ modules/liveintentAnalyticsAdapter.md | 3 +- .../liveIntentAnalyticsAdapter_spec.js | 39 ++++++++++++++++++- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 06b52074722..94f381e0160 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -17,7 +17,7 @@ let liAnalytics = Object.assign(adapter({url, analyticsType}), { if (typeof args !== 'undefined') { switch (eventType) { case AUCTION_END: - handleAuctionEnd(args); + liAnalytics.handleAuctionEnd(args); break; default: break; } @@ -25,15 +25,18 @@ let liAnalytics = Object.assign(adapter({url, analyticsType}), { } }); -function handleAuctionEnd(args) { - const bidWonTimeout = initOptions.bidWonTimeout || 2000; - setTimeout(() => { - let auction = auctionManager.index.getAuction(args.auctionId); - let winningBids = (auction) ? auction.getWinningBids() : []; - // sampling? - let data = liAnalytics.createAnalyticsEvent(args, winningBids); - sendAnalyticsEvent(data); - }, bidWonTimeout); +liAnalytics.handleAuctionEnd = function(args) { + const bidWonTimeout = (initOptions && initOptions.bidWonTimeout) || 2000; + const sampling = (initOptions && initOptions.sampling) || 0.1; + const isSampled = Math.random() < parseFloat(sampling) + if (isSampled) { + setTimeout(() => { + const auction = auctionManager.index.getAuction(args.auctionId); + const winningBids = (auction) ? auction.getWinningBids() : []; + const data = liAnalytics.createAnalyticsEvent(args, winningBids); + sendAnalyticsEvent(data); + }, bidWonTimeout); + } } function getAnalyticsEventBids(bidsReceived) { @@ -92,7 +95,7 @@ liAnalytics.createAnalyticsEvent = function(args, winningBids) { payload['bidders'].push(...bidders); }) - let uniqueUserIds = getUniqueBy(allUserIds, 'source') // TODO remove duplicates???? + let uniqueUserIds = getUniqueBy(allUserIds, 'source') payload['userIds'] = uniqueUserIds payload['winningBids'] = getAnalyticsEventBids(winningBids); payload['auctionId'] = args.auctionId; diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveintentAnalyticsAdapter.md index f0da8aefc1f..adc2a160503 100644 --- a/modules/liveintentAnalyticsAdapter.md +++ b/modules/liveintentAnalyticsAdapter.md @@ -14,7 +14,8 @@ Analytics adapter for Example.com. Contact prebid@example.com for information. P { provider: 'liveintent', options: { - bidWonTimeout: 2000 + bidWonTimeout: 2000, + sampling: 0.5 // the tracked event percentage, a number between 0 to 1 } } ``` diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index a24d5798034..d5e9ef68baa 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -1,6 +1,15 @@ import liAnalytics from '../../../modules/liveintentAnalyticsAdapter'; import { expect } from 'chai'; +let utils = require('src/utils'); +let instanceId = '77abbc81-c1f1-41cd-8f25-f7149244c800'; +let url = window.location.href; +let constants = require('src/constants.json'); +let sandbox; +let clock; +let now = new Date(); +let events = require('src/events'); + let args = { auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', timestamp: 1660915379703, @@ -23,8 +32,10 @@ let args = { } }, ortb2Imp: { + gpid: '/777/test/home/ID_Bot100AdJ1', ext: { data: { + aupName: '/777/test/home/ID_Bot100AdJ1', adserver: { name: 'gam', adslot: '/777/test/home/ID_Bot100AdJ1' @@ -127,6 +138,18 @@ let winningBids = [ ]; describe('LiveIntent Analytics Adapter ', () => { + beforeEach(function () { + sinon.stub(events, 'getEvents').returns([]); + sandbox = sinon.sandbox.create(); + clock = sandbox.useFakeTimers(now.getTime()); + }); + afterEach(function () { + events.getEvents.restore() + liAnalytics.disableAnalytics(); + sandbox.restore(); + clock.restore(); + }); + it('extract sizes', function () { let expectedResult = [{ w: 100, @@ -142,8 +165,8 @@ describe('LiveIntent Analytics Adapter ', () => { it('creates analytics event from args and winning bids', () => { let expectedResult = { - instanceId: '77abbc81-c1f1-41cd-8f25-f7149244c800', - url: 'https://test.com/', + instanceId: instanceId, + url: url, bidsReceived: [ { adUnitCode: 'ID_Bot100AdJ1', @@ -242,6 +265,18 @@ describe('LiveIntent Analytics Adapter ', () => { } ] }; + const initOptions = { + provider: 'liveintent', + options: { + bidWonTimeout: 2000, + sampling: 1 + } + } + sandbox.stub(liAnalytics, 'handleAuctionEnd'); + liAnalytics.enableAnalytics(initOptions); + events.emit(constants.EVENTS.AUCTION_END, args); + sinon.stub(utils, 'generateUUID').returns('77abbc81-c1f1-41cd-8f25-f7149244c800') expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); + expect(liAnalytics.handleAuctionEnd.called).to.equal(true) }); }); From f231ce4dfe9c1ca542f8a12793b9fdd197804b7e Mon Sep 17 00:00:00 2001 From: leonelcuevas Date: Thu, 1 Sep 2022 18:06:41 +0200 Subject: [PATCH 08/17] Add server test --- modules/liveintentAnalyticsAdapter.js | 4 +- .../liveIntentAnalyticsAdapter_spec.js | 55 +++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveintentAnalyticsAdapter.js index 94f381e0160..49ed51c4ea1 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveintentAnalyticsAdapter.js @@ -2,7 +2,7 @@ import {ajax} from '../src/ajax.js'; import { generateUUID, logInfo } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adaptermanager from '../src/adaptermanager.js'; +import adapterManager from '../src/adapterManager.js'; import { auctionManager } from '../src/auctionManager.js'; const analyticsType = 'endpoint'; @@ -148,7 +148,7 @@ liAnalytics.enableAnalytics = function (config) { liAnalytics.originEnableAnalytics(config); // call the base class function }; -adaptermanager.registerAnalyticsAdapter({ +adapterManager.registerAnalyticsAdapter({ adapter: liAnalytics, code: adapterCode, gvlid: gvlid diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index d5e9ef68baa..8e10a979082 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -1,14 +1,18 @@ -import liAnalytics from '../../../modules/liveintentAnalyticsAdapter'; +import liAnalytics from 'modules/liveintentAnalyticsAdapter'; import { expect } from 'chai'; +import { server } from 'test/mocks/xhr.js'; +import { auctionManager } from 'src/auctionManager.js'; +// import { auctionManager } from 'src/auctionManager.js'; let utils = require('src/utils'); let instanceId = '77abbc81-c1f1-41cd-8f25-f7149244c800'; let url = window.location.href; -let constants = require('src/constants.json'); let sandbox; let clock; let now = new Date(); + let events = require('src/events'); +let constants = require('src/constants.json'); let args = { auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', @@ -137,19 +141,48 @@ let winningBids = [ } ]; +const config = { + provider: 'liveintent', + options: { + bidWonTimeout: 2000, + sampling: 1 + } +} + describe('LiveIntent Analytics Adapter ', () => { beforeEach(function () { - sinon.stub(events, 'getEvents').returns([]); sandbox = sinon.sandbox.create(); + sandbox.stub(events, 'getEvents').returns([]); clock = sandbox.useFakeTimers(now.getTime()); }); afterEach(function () { - events.getEvents.restore() liAnalytics.disableAnalytics(); sandbox.restore(); clock.restore(); }); + it('request is sent correctly', () => { + liAnalytics.enableAnalytics(config); + events.emit(constants.EVENTS.AUCTION_END, args); + clock.tick(2000); + sandbox.stub(auctionManager.index, 'getAuction').withArgs('99abbc81-c1f1-41cd-8f25-f7149244c897').returns({}) + expect(server.requests.length).to.equal(1); + }); + + it('calls handleAuctionEnd when an AUCTION_END event is received', () => { + liAnalytics.enableAnalytics(config); + sandbox.stub(liAnalytics, 'handleAuctionEnd'); + events.emit(constants.EVENTS.AUCTION_END, args); + sandbox.assert.calledOnce(liAnalytics.handleAuctionEnd); + }); + + it('not call handleAuctionEnd when another event type is received', () => { + liAnalytics.enableAnalytics(config); + sandbox.stub(liAnalytics, 'handleAuctionEnd'); + events.emit(constants.EVENTS.BID_TIMEOUT, args); + sandbox.assert.notCalled(liAnalytics.handleAuctionEnd); + }); + it('extract sizes', function () { let expectedResult = [{ w: 100, @@ -265,18 +298,8 @@ describe('LiveIntent Analytics Adapter ', () => { } ] }; - const initOptions = { - provider: 'liveintent', - options: { - bidWonTimeout: 2000, - sampling: 1 - } - } - sandbox.stub(liAnalytics, 'handleAuctionEnd'); - liAnalytics.enableAnalytics(initOptions); - events.emit(constants.EVENTS.AUCTION_END, args); - sinon.stub(utils, 'generateUUID').returns('77abbc81-c1f1-41cd-8f25-f7149244c800') + + sandbox.stub(utils, 'generateUUID').returns('77abbc81-c1f1-41cd-8f25-f7149244c800') expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); - expect(liAnalytics.handleAuctionEnd.called).to.equal(true) }); }); From 3284324ac5d106ddf51ce0d71703751ff640658b Mon Sep 17 00:00:00 2001 From: leonelcuevas Date: Fri, 2 Sep 2022 10:37:12 +0200 Subject: [PATCH 09/17] Compare expected request body in the test --- .../liveIntentAnalyticsAdapter_spec.js | 233 +++++++++--------- 1 file changed, 119 insertions(+), 114 deletions(-) diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index 8e10a979082..bd8b7ed6566 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -13,9 +13,18 @@ let now = new Date(); let events = require('src/events'); let constants = require('src/constants.json'); +let auctionId = '99abbc81-c1f1-41cd-8f25-f7149244c897' + +const config = { + provider: 'liveintent', + options: { + bidWonTimeout: 2000, + sampling: 1 + } +} let args = { - auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', + auctionId: auctionId, timestamp: 1660915379703, auctionEnd: 1660915381635, adUnits: [ @@ -141,13 +150,107 @@ let winningBids = [ } ]; -const config = { - provider: 'liveintent', - options: { - bidWonTimeout: 2000, - sampling: 1 - } -} +let expectedEvent = { + instanceId: instanceId, + url: url, + bidsReceived: [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } + ], + auctionStart: 1660915379703, + auctionEnd: 1660915381635, + adUnits: [ + { + code: 'ID_Bot100AdJ1', + mediaType: 'banner', + sizes: [ + { + w: 300, + h: 250 + }, + { + w: 320, + h: 50 + } + ], + ortb2Imp: { + gpid: '/777/test/home/ID_Bot100AdJ1', + ext: { + data: { + aupName: '/777/test/home/ID_Bot100AdJ1', + adserver: { + name: 'gam', + adslot: '/777/test/home/ID_Bot100AdJ1' + }, + pbadslot: '/777/test/home/ID_Bot100AdJ1' + }, + gpid: '/777/test/home/ID_Bot100AdJ1' + } + } + } + ], + winningBids: [ + { + adUnitCode: 'ID_Bot100AdJ1', + timeToRespond: 824, + cpm: 0.447, + currency: 'USD', + ttl: 300, + bidder: 'testBidder' + } + ], + auctionId: auctionId, + userIds: [ + { + source: 'source1.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + }, + { + source: 'source2.com', + uids: [ + { + id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', + atype: 1, + ext: { + linkType: 2 + } + } + ] + } + ], + bidders: [ + { + bidder: 'testBidder', + params: { + siteId: 321218, + zoneId: 1732558, + position: 'bug', + accountId: 10777 + } + }, + { + bidder: 'testBidder2', + params: { + adSlot: '2926251', + publisherId: '159423' + } + } + ] +}; describe('LiveIntent Analytics Adapter ', () => { beforeEach(function () { @@ -163,10 +266,14 @@ describe('LiveIntent Analytics Adapter ', () => { it('request is sent correctly', () => { liAnalytics.enableAnalytics(config); + sandbox.stub(utils, 'generateUUID').returns(instanceId); + sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids }) events.emit(constants.EVENTS.AUCTION_END, args); clock.tick(2000); - sandbox.stub(auctionManager.index, 'getAuction').withArgs('99abbc81-c1f1-41cd-8f25-f7149244c897').returns({}) expect(server.requests.length).to.equal(1); + + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(requestBody).to.deep.equal(expectedEvent); }); it('calls handleAuctionEnd when an AUCTION_END event is received', () => { @@ -183,7 +290,7 @@ describe('LiveIntent Analytics Adapter ', () => { sandbox.assert.notCalled(liAnalytics.handleAuctionEnd); }); - it('extract sizes', function () { + it('extract sizes', () => { let expectedResult = [{ w: 100, h: 50 @@ -197,109 +304,7 @@ describe('LiveIntent Analytics Adapter ', () => { }); it('creates analytics event from args and winning bids', () => { - let expectedResult = { - instanceId: instanceId, - url: url, - bidsReceived: [ - { - adUnitCode: 'ID_Bot100AdJ1', - timeToRespond: 824, - cpm: 0.447, - currency: 'USD', - ttl: 300, - bidder: 'testBidder' - } - ], - auctionStart: 1660915379703, - auctionEnd: 1660915381635, - adUnits: [ - { - code: 'ID_Bot100AdJ1', - mediaType: 'banner', - sizes: [ - { - w: 300, - h: 250 - }, - { - w: 320, - h: 50 - } - ], - ortb2Imp: { - gpid: '/777/test/home/ID_Bot100AdJ1', - ext: { - data: { - aupName: '/777/test/home/ID_Bot100AdJ1', - adserver: { - name: 'gam', - adslot: '/777/test/home/ID_Bot100AdJ1' - }, - pbadslot: '/777/test/home/ID_Bot100AdJ1' - }, - gpid: '/777/test/home/ID_Bot100AdJ1' - } - } - } - ], - winningBids: [ - { - adUnitCode: 'ID_Bot100AdJ1', - timeToRespond: 824, - cpm: 0.447, - currency: 'USD', - ttl: 300, - bidder: 'testBidder' - } - ], - auctionId: '99abbc81-c1f1-41cd-8f25-f7149244c897', - userIds: [ - { - source: 'source1.com', - uids: [ - { - id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', - atype: 1, - ext: { - linkType: 2 - } - } - ] - }, - { - source: 'source2.com', - uids: [ - { - id: 'ID5*yO-L9xRugTx4mkIJ9z99eYva6CZQhz8B70QOkLLSEEQWowsxvVQqMaZOt4qpBTYAFqR3y6ZtZ8qLJJBAsRqnRRalTfy8iZszQavAAkZcAjkWpxp6DnOSkF3R5LafC10OFqhwcxH699dDc_fI6RVEGBasN6zrJwgqCGelgfQLtQwWrikWRyi0l3ICFj9JUiVGFrCF8SAFaqJD9A0_I07a8xa0-jADtEj1T8w30oX--sMWvTK_I5_3zA5f3z0OMoxbFsCMFdhfGRDuw5GrpI475g', - atype: 1, - ext: { - linkType: 2 - } - } - ] - } - ], - bidders: [ - { - bidder: 'testBidder', - params: { - siteId: 321218, - zoneId: 1732558, - position: 'bug', - accountId: 10777 - } - }, - { - bidder: 'testBidder2', - params: { - adSlot: '2926251', - publisherId: '159423' - } - } - ] - }; - - sandbox.stub(utils, 'generateUUID').returns('77abbc81-c1f1-41cd-8f25-f7149244c800') - expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedResult); + sandbox.stub(utils, 'generateUUID').returns(instanceId) + expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedEvent); }); }); From d0037d4dc85da1105be08f2c5be6ec6659318812 Mon Sep 17 00:00:00 2001 From: wiem Date: Fri, 2 Sep 2022 11:45:59 +0200 Subject: [PATCH 10/17] refactoring --- modules/liveintentAnalyticsAdapter.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveintentAnalyticsAdapter.md index adc2a160503..4f27adb45aa 100644 --- a/modules/liveintentAnalyticsAdapter.md +++ b/modules/liveintentAnalyticsAdapter.md @@ -1,7 +1,8 @@ # Overview - Module Name: LiveIntent Analytics Adapter + Module Type: Analytics Adapter + Maintainer: prebid@example.com # Description From 9a1dbfef4e80c57ab64093b43f6ce9bb39d7e573 Mon Sep 17 00:00:00 2001 From: wiem Date: Fri, 2 Sep 2022 11:52:49 +0200 Subject: [PATCH 11/17] update description --- modules/liveintentAnalyticsAdapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveintentAnalyticsAdapter.md index 4f27adb45aa..7461d8a04e3 100644 --- a/modules/liveintentAnalyticsAdapter.md +++ b/modules/liveintentAnalyticsAdapter.md @@ -7,7 +7,7 @@ Maintainer: prebid@example.com # Description -Analytics adapter for Example.com. Contact prebid@example.com for information. Provided by LiveIntent +Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact prebid@example.com for information. # Test Parameters From b8790cc9561c84053866ee8b621084014fe49f8c Mon Sep 17 00:00:00 2001 From: wiem Date: Fri, 2 Sep 2022 12:21:46 +0200 Subject: [PATCH 12/17] remove comment --- test/spec/modules/liveIntentAnalyticsAdapter_spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index bd8b7ed6566..3faafd21faf 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; import { auctionManager } from 'src/auctionManager.js'; -// import { auctionManager } from 'src/auctionManager.js'; let utils = require('src/utils'); let instanceId = '77abbc81-c1f1-41cd-8f25-f7149244c800'; let url = window.location.href; From 3cff7ed199cb61028b5123630d9e13c3acdbfc7e Mon Sep 17 00:00:00 2001 From: wiem Date: Mon, 5 Sep 2022 15:12:12 +0200 Subject: [PATCH 13/17] comments --- ...sAdapter.js => liveIntentAnalyticsAdapter.js} | 16 +++++----------- ...sAdapter.md => liveIntentAnalyticsAdapter.md} | 4 ++-- 2 files changed, 7 insertions(+), 13 deletions(-) rename modules/{liveintentAnalyticsAdapter.js => liveIntentAnalyticsAdapter.js} (93%) rename modules/{liveintentAnalyticsAdapter.md => liveIntentAnalyticsAdapter.md} (80%) diff --git a/modules/liveintentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js similarity index 93% rename from modules/liveintentAnalyticsAdapter.js rename to modules/liveIntentAnalyticsAdapter.js index 49ed51c4ea1..61185f0bbb1 100644 --- a/modules/liveintentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -10,25 +10,17 @@ const url = 'https://wba.liadm.com/analytic-events'; const gvlid = 148; const adapterCode = 'liveintent'; const { EVENTS: { AUCTION_END } } = CONSTANTS; -let initOptions = {} +let initOptions = {}; +let isSampled; let liAnalytics = Object.assign(adapter({url, analyticsType}), { track({ eventType, args }) { - if (typeof args !== 'undefined') { - switch (eventType) { - case AUCTION_END: - liAnalytics.handleAuctionEnd(args); - break; - default: break; - } - } + if (eventType == AUCTION_END && args) { liAnalytics.handleAuctionEnd(args); } } }); liAnalytics.handleAuctionEnd = function(args) { const bidWonTimeout = (initOptions && initOptions.bidWonTimeout) || 2000; - const sampling = (initOptions && initOptions.sampling) || 0.1; - const isSampled = Math.random() < parseFloat(sampling) if (isSampled) { setTimeout(() => { const auction = auctionManager.index.getAuction(args.auctionId); @@ -145,6 +137,8 @@ liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; // override enableAnalytics so we can get access to the config passed in from the page liAnalytics.enableAnalytics = function (config) { initOptions = config.options; + const sampling = (initOptions && initOptions.sampling) || 0.1; + isSampled = Math.random() < parseFloat(sampling); liAnalytics.originEnableAnalytics(config); // call the base class function }; diff --git a/modules/liveintentAnalyticsAdapter.md b/modules/liveIntentAnalyticsAdapter.md similarity index 80% rename from modules/liveintentAnalyticsAdapter.md rename to modules/liveIntentAnalyticsAdapter.md index 7461d8a04e3..36eebbb0600 100644 --- a/modules/liveintentAnalyticsAdapter.md +++ b/modules/liveIntentAnalyticsAdapter.md @@ -3,11 +3,11 @@ Module Name: LiveIntent Analytics Adapter Module Type: Analytics Adapter -Maintainer: prebid@example.com +Maintainer: tam@liveintenteng.com # Description -Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact prebid@example.com for information. +Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact tam@liveintenteng.com for information. # Test Parameters From 25d0013b01144aede259ac04aae4c39e512f9454 Mon Sep 17 00:00:00 2001 From: wiem Date: Mon, 5 Sep 2022 15:48:25 +0200 Subject: [PATCH 14/17] make sure we map defined data --- modules/liveIntentAnalyticsAdapter.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/liveIntentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js index 61185f0bbb1..d72f5773ff5 100644 --- a/modules/liveIntentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -102,14 +102,16 @@ function getBidder(bid) { } function getAnalyticsEventUserIds(bid) { - return bid.userIdAsEids.map(userId => { - let analyticsEventUserId = { - source: userId.source, - uids: userId.uids, - ext: userId.ext - }; - return ignoreUndefined(analyticsEventUserId) - }); + if (bid && bid.userIdAsEids) { + return bid.userIdAsEids.map(userId => { + let analyticsEventUserId = { + source: userId.source, + uids: userId.uids, + ext: userId.ext + }; + return ignoreUndefined(analyticsEventUserId) + }); + } else { return []; } } function sendAnalyticsEvent(data) { From 9998926bcb74bcddf6826fbbcfd4032eb28bfd91 Mon Sep 17 00:00:00 2001 From: wiem Date: Tue, 6 Sep 2022 14:18:34 +0200 Subject: [PATCH 15/17] refactoring --- modules/liveIntentAnalyticsAdapter.js | 49 ++++++++++--------- .../liveIntentAnalyticsAdapter_spec.js | 8 +++ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/modules/liveIntentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js index d72f5773ff5..367a4236707 100644 --- a/modules/liveIntentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -45,10 +45,12 @@ function getAnalyticsEventBids(bidsReceived) { } liAnalytics.getBannerSizes = function(banner) { - return banner.sizes.map(size => { - const [width, height] = size; - return {w: width, h: height}; - }); + if (banner && banner.sizes) { + return banner.sizes.map(size => { + const [width, height] = size; + return {w: width, h: height}; + }); + } else return []; } function getUniqueBy(arr, key) { @@ -70,25 +72,26 @@ liAnalytics.createAnalyticsEvent = function(args, winningBids) { payload['userIds'] = []; payload['bidders'] = []; - args.adUnits.forEach(unit => { - if (unit.mediaTypes && unit.mediaTypes.banner) { - payload['adUnits'].push({ - code: unit.code, - mediaType: 'banner', - sizes: liAnalytics.getBannerSizes(unit.mediaTypes.banner), - ortb2Imp: unit.ortb2Imp - }); - } - - let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); - allUserIds.push(...userIds); - - let bidders = unit.bids.map(getBidder); - payload['bidders'].push(...bidders); - }) - - let uniqueUserIds = getUniqueBy(allUserIds, 'source') - payload['userIds'] = uniqueUserIds + if (args.adUnits) { + args.adUnits.forEach(unit => { + if (unit.mediaTypes && unit.mediaTypes.banner) { + payload['adUnits'].push({ + code: unit.code, + mediaType: 'banner', + sizes: liAnalytics.getBannerSizes(unit.mediaTypes.banner), + ortb2Imp: unit.ortb2Imp + }); + } + if (unit.bids) { + let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); + allUserIds.push(...userIds); + let bidders = unit.bids.map(getBidder); + payload['bidders'].push(...bidders); + } + }) + let uniqueUserIds = getUniqueBy(allUserIds, 'source'); + payload['userIds'] = uniqueUserIds; + } payload['winningBids'] = getAnalyticsEventBids(winningBids); payload['auctionId'] = args.auctionId; return payload; diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index 3faafd21faf..db087d6e582 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -119,9 +119,17 @@ let args = { ], bidderRequests: [ { + bidderCode: 'tripl_ss1', + auctionId: '8e5a5eda-a7dc-49a3-bc7f-654fc', + bidderRequestId: '953fe1ee8a1645', + uniquePbsTid: '0da1f980-8351-415d-860d-ebbdb4274179', auctionStart: 1660915379703 }, { + bidderCode: 'tripl_ss2', + auctionId: '8e5a5eda-a7dc-49a3-bc7f-6ca682ae893c', + bidderRequestId: '953fe1ee8a164e', + uniquePbsTid: '0da1f980-8351-415d-860d-ebbdb4274180', auctionStart: 1660915379703 } ], From ff4130d3130c37668af3a9e1a1f287ddf79c0755 Mon Sep 17 00:00:00 2001 From: wiem Date: Tue, 6 Sep 2022 17:20:54 +0200 Subject: [PATCH 16/17] some refactoring --- modules/liveIntentAnalyticsAdapter.js | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/modules/liveIntentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js index 367a4236707..858cd6c11e2 100644 --- a/modules/liveIntentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -5,30 +5,30 @@ import CONSTANTS from '../src/constants.json'; import adapterManager from '../src/adapterManager.js'; import { auctionManager } from '../src/auctionManager.js'; -const analyticsType = 'endpoint'; -const url = 'https://wba.liadm.com/analytic-events'; -const gvlid = 148; -const adapterCode = 'liveintent'; +const ANALYTICS_TYPE = 'endpoint'; +const URL = 'https://wba.liadm.com/analytic-events'; +const GVL_ID = 148; +const ADAPTER_CODE = 'liveintent'; +const DEFAULT_SAMPLING = 0.1; +const DEFAULT_BID_WON_TIMEOUT = 2000; const { EVENTS: { AUCTION_END } } = CONSTANTS; let initOptions = {}; let isSampled; +let bidWonTimeout; -let liAnalytics = Object.assign(adapter({url, analyticsType}), { +let liAnalytics = Object.assign(adapter({URL, ANALYTICS_TYPE}), { track({ eventType, args }) { - if (eventType == AUCTION_END && args) { liAnalytics.handleAuctionEnd(args); } + if (eventType == AUCTION_END && args && isSampled) { liAnalytics.handleAuctionEnd(args); } } }); liAnalytics.handleAuctionEnd = function(args) { - const bidWonTimeout = (initOptions && initOptions.bidWonTimeout) || 2000; - if (isSampled) { - setTimeout(() => { - const auction = auctionManager.index.getAuction(args.auctionId); - const winningBids = (auction) ? auction.getWinningBids() : []; - const data = liAnalytics.createAnalyticsEvent(args, winningBids); - sendAnalyticsEvent(data); - }, bidWonTimeout); - } + setTimeout(() => { + const auction = auctionManager.index.getAuction(args.auctionId); + const winningBids = (auction) ? auction.getWinningBids() : []; + const data = liAnalytics.createAnalyticsEvent(args, winningBids); + sendAnalyticsEvent(data); + }, bidWonTimeout); } function getAnalyticsEventBids(bidsReceived) { @@ -118,7 +118,7 @@ function getAnalyticsEventUserIds(bid) { } function sendAnalyticsEvent(data) { - ajax(url, { + ajax(URL, { success: function () { logInfo('LiveIntent Prebid Analytics: send data success'); }, @@ -142,15 +142,16 @@ liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; // override enableAnalytics so we can get access to the config passed in from the page liAnalytics.enableAnalytics = function (config) { initOptions = config.options; - const sampling = (initOptions && initOptions.sampling) || 0.1; + const sampling = (initOptions && initOptions.sampling) || DEFAULT_SAMPLING; isSampled = Math.random() < parseFloat(sampling); + bidWonTimeout = (initOptions && initOptions.bidWonTimeout) || DEFAULT_BID_WON_TIMEOUT; liAnalytics.originEnableAnalytics(config); // call the base class function }; adapterManager.registerAnalyticsAdapter({ adapter: liAnalytics, - code: adapterCode, - gvlid: gvlid + code: ADAPTER_CODE, + gvlid: GVL_ID }); export default liAnalytics; From 0220f438934261fbc8643b39793c299bcb954f9e Mon Sep 17 00:00:00 2001 From: wiem Date: Wed, 7 Sep 2022 12:13:03 +0200 Subject: [PATCH 17/17] comments --- modules/liveIntentAnalyticsAdapter.js | 68 ++++++++----------- modules/liveIntentAnalyticsAdapter.md | 4 +- .../liveIntentAnalyticsAdapter_spec.js | 40 +++-------- 3 files changed, 40 insertions(+), 72 deletions(-) diff --git a/modules/liveIntentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js index 858cd6c11e2..b702e4a319a 100644 --- a/modules/liveIntentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -1,5 +1,5 @@ import {ajax} from '../src/ajax.js'; -import { generateUUID, logInfo } from '../src/utils.js'; +import { generateUUID, logInfo, logWarn } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; import adapterManager from '../src/adapterManager.js'; @@ -16,17 +16,11 @@ let initOptions = {}; let isSampled; let bidWonTimeout; -let liAnalytics = Object.assign(adapter({URL, ANALYTICS_TYPE}), { - track({ eventType, args }) { - if (eventType == AUCTION_END && args && isSampled) { liAnalytics.handleAuctionEnd(args); } - } -}); - -liAnalytics.handleAuctionEnd = function(args) { +function handleAuctionEnd(args) { setTimeout(() => { const auction = auctionManager.index.getAuction(args.auctionId); const winningBids = (auction) ? auction.getWinningBids() : []; - const data = liAnalytics.createAnalyticsEvent(args, winningBids); + const data = createAnalyticsEvent(args, winningBids); sendAnalyticsEvent(data); }, bidWonTimeout); } @@ -44,7 +38,7 @@ function getAnalyticsEventBids(bidsReceived) { }); } -liAnalytics.getBannerSizes = function(banner) { +function getBannerSizes(banner) { if (banner && banner.sizes) { return banner.sizes.map(size => { const [width, height] = size; @@ -57,35 +51,36 @@ function getUniqueBy(arr, key) { return [...new Map(arr.map(item => [item[key], item])).values()] } -liAnalytics.createAnalyticsEvent = function(args, winningBids) { - let payload = {} +function createAnalyticsEvent(args, winningBids) { + let payload = { + instanceId: generateUUID(), + url: window.location.href, + bidsReceived: getAnalyticsEventBids(args.bidsReceived), + auctionStart: args.timestamp, + auctionEnd: args.auctionEnd, + adUnits: [], + userIds: [], + bidders: [] + } let allUserIds = []; - payload['instanceId'] = generateUUID(); - payload['url'] = window.location.href; - payload['bidsReceived'] = getAnalyticsEventBids(args.bidsReceived); - - payload['auctionStart'] = args.timestamp; - payload['auctionEnd'] = args.auctionEnd; - - payload['adUnits'] = []; - payload['userIds'] = []; - payload['bidders'] = []; - if (args.adUnits) { args.adUnits.forEach(unit => { if (unit.mediaTypes && unit.mediaTypes.banner) { payload['adUnits'].push({ code: unit.code, mediaType: 'banner', - sizes: liAnalytics.getBannerSizes(unit.mediaTypes.banner), + sizes: getBannerSizes(unit.mediaTypes.banner), ortb2Imp: unit.ortb2Imp }); } if (unit.bids) { let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); allUserIds.push(...userIds); - let bidders = unit.bids.map(getBidder); + let bidders = unit.bids.map(({bidder, params}) => { + return { bidder, params } + }); + payload['bidders'].push(...bidders); } }) @@ -97,21 +92,10 @@ liAnalytics.createAnalyticsEvent = function(args, winningBids) { return payload; } -function getBidder(bid) { - return { - bidder: bid.bidder, - params: bid.params - }; -} - function getAnalyticsEventUserIds(bid) { if (bid && bid.userIdAsEids) { - return bid.userIdAsEids.map(userId => { - let analyticsEventUserId = { - source: userId.source, - uids: userId.uids, - ext: userId.ext - }; + return bid.userIdAsEids.map(({source, uids, ext}) => { + let analyticsEventUserId = {source, uids, ext}; return ignoreUndefined(analyticsEventUserId) }); } else { return []; } @@ -123,7 +107,7 @@ function sendAnalyticsEvent(data) { logInfo('LiveIntent Prebid Analytics: send data success'); }, error: function (e) { - logInfo('LiveIntent Prebid Analytics: send data error' + e); + logWarn('LiveIntent Prebid Analytics: send data error' + e); } }, JSON.stringify(data), { contentType: 'application/json', @@ -136,6 +120,12 @@ function ignoreUndefined(data) { return Object.fromEntries(filteredData) } +let liAnalytics = Object.assign(adapter({URL, ANALYTICS_TYPE}), { + track({ eventType, args }) { + if (eventType == AUCTION_END && args && isSampled) { handleAuctionEnd(args); } + } +}); + // save the base class function liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; diff --git a/modules/liveIntentAnalyticsAdapter.md b/modules/liveIntentAnalyticsAdapter.md index 36eebbb0600..15f51006134 100644 --- a/modules/liveIntentAnalyticsAdapter.md +++ b/modules/liveIntentAnalyticsAdapter.md @@ -3,11 +3,11 @@ Module Name: LiveIntent Analytics Adapter Module Type: Analytics Adapter -Maintainer: tam@liveintenteng.com +Maintainer: product@liveintent.com # Description -Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact tam@liveintenteng.com for information. +Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact product@liveintent.com for information. # Test Parameters diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index db087d6e582..413bb7ec03f 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -271,10 +271,10 @@ describe('LiveIntent Analytics Adapter ', () => { clock.restore(); }); - it('request is sent correctly', () => { + it('request is computed and sent correctly', () => { liAnalytics.enableAnalytics(config); sandbox.stub(utils, 'generateUUID').returns(instanceId); - sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids }) + sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids }); events.emit(constants.EVENTS.AUCTION_END, args); clock.tick(2000); expect(server.requests.length).to.equal(1); @@ -283,35 +283,13 @@ describe('LiveIntent Analytics Adapter ', () => { expect(requestBody).to.deep.equal(expectedEvent); }); - it('calls handleAuctionEnd when an AUCTION_END event is received', () => { + it('track is called', () => { liAnalytics.enableAnalytics(config); - sandbox.stub(liAnalytics, 'handleAuctionEnd'); + sandbox.stub(liAnalytics, 'track'); events.emit(constants.EVENTS.AUCTION_END, args); - sandbox.assert.calledOnce(liAnalytics.handleAuctionEnd); - }); - - it('not call handleAuctionEnd when another event type is received', () => { - liAnalytics.enableAnalytics(config); - sandbox.stub(liAnalytics, 'handleAuctionEnd'); - events.emit(constants.EVENTS.BID_TIMEOUT, args); - sandbox.assert.notCalled(liAnalytics.handleAuctionEnd); - }); - - it('extract sizes', () => { - let expectedResult = [{ - w: 100, - h: 50 - }]; - let banner = { - sizes: [ - [100, 50] - ] - }; - expect(liAnalytics.getBannerSizes(banner)).to.deep.equal(expectedResult); - }); - - it('creates analytics event from args and winning bids', () => { - sandbox.stub(utils, 'generateUUID').returns(instanceId) - expect(liAnalytics.createAnalyticsEvent(args, winningBids)).to.deep.equal(expectedEvent); - }); + events.emit(constants.EVENTS.AUCTION_END, args); + events.emit(constants.EVENTS.AUCTION_END, args); + clock.tick(6000); + sinon.assert.callCount(liAnalytics.track, 3) + }) });