diff --git a/modules/adagioAnalyticsAdapter.js b/modules/adagioAnalyticsAdapter.js index ddcf178c5fb..033809e7f1b 100644 --- a/modules/adagioAnalyticsAdapter.js +++ b/modules/adagioAnalyticsAdapter.js @@ -3,7 +3,7 @@ */ import { _ADAGIO, getBestWindowForAdagio } from '../libraries/adagioUtils/adagioUtils.js'; -import { deepAccess, logError, logInfo } from '../src/utils.js'; +import { deepAccess, logError, logInfo, logWarn } from '../src/utils.js'; import { BANNER } from '../src/mediaTypes.js'; import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; @@ -130,6 +130,10 @@ function getCurrencyData(bid) { * @param {Object} qp */ function sendRequest(qp) { + if (!qp.org_id || !qp.site) { + logInfo('request is missing org_id or site, skipping beacon.'); + return; + } // Removing null values qp = Object.keys(qp).reduce((acc, key) => { if (qp[key] !== null) { @@ -180,33 +184,22 @@ function handlerAuctionInit(event) { const adUnitCodes = removeDuplicates(event.adUnitCodes, adUnitCode => adUnitCode); // Check if Adagio is on the bid requests. - // If not, we don't need to track the auction. const adagioBidRequest = event.bidderRequests.find(bidRequest => isAdagio(bidRequest.bidderCode)); - if (!adagioBidRequest) { - logInfo(`Adagio is not on the bid requests for auction '${prebidAuctionId}'`) - return; - } + const rtdUid = deepAccess(adagioBidRequest, 'ortb2.site.ext.data.adg_rtd.uid'); cache.addPrebidAuctionIdRef(prebidAuctionId, rtdUid); cache.auctions[prebidAuctionId] = {}; adUnitCodes.forEach(adUnitCode => { + // event.adUnits are splitted by mediatypes const adUnits = event.adUnits.filter(adUnit => adUnit.code === adUnitCode); - // Get all bidders configures for the ad unit. - const bidders = removeDuplicates( - adUnits.map(adUnit => adUnit.bids.map(bid => ({bidder: bid.bidder, params: bid.params}))).flat(), - bidder => bidder.bidder - ); - - // Check if Adagio is configured for the ad unit. - // If not, we don't need to track the ad unit. - const adagioBidder = bidders.find(bidder => isAdagio(bidder.bidder)); - if (!adagioBidder) { - logInfo(`Adagio is not configured for ad unit '${adUnitCode}'`); - return; - } + // Get all bidders configured for the ad unit. + // AdUnits with the same code can have a different bidder list, aggregate all of them. + const biddersAggregate = adUnits.reduce((bidders, adUnit) => bidders.concat(adUnit.bids.map(bid => bid.bidder)), []) + // remove duplicates + const bidders = [...new Set(biddersAggregate)]; // Get all media types and banner sizes configured for the ad unit. const mediaTypes = adUnits.map(adUnit => adUnit.mediaTypes); @@ -221,45 +214,56 @@ function handlerAuctionInit(event) { bannerSize => bannerSize ).sort(); - // Get all Adagio bids for the ad unit from the bidRequest. - // If no bids, we don't need to track the ad unit. - const adagioAdUnitBids = adagioBidRequest.bids.filter(bid => bid.adUnitCode === adUnitCode); - if (deepAccess(adagioAdUnitBids, 'length', 0) <= 0) { - logInfo(`Adagio is not on the bid requests for ad unit '${adUnitCode}' and auction '${prebidAuctionId}'`) - return; - } - // Get Adagio params from the first bid. - // We assume that all Adagio bids for a same adunit have the same params. - const params = adagioAdUnitBids[0].params; + const sortedBidderCodes = bidders.sort() - // Get all media types requested for Adagio. - const adagioMediaTypes = removeDuplicates( - adagioAdUnitBids.map(bid => Object.keys(bid.mediaTypes)).flat(), - mediaTypeKey => mediaTypeKey - ).flat().map(mediaType => getMediaTypeAlias(mediaType)).sort(); + const bidSrcMapper = (bidder) => { + const request = event.bidderRequests.find(br => br.bidderCode === bidder) + return request ? request.bids[0].src : null + } + const biddersSrc = sortedBidderCodes.map(bidSrcMapper).join(','); // if adagio was involved in the auction we identified it with rtdUid, if not use the prebid auctionId - let auctionId = rtdUid || prebidAuctionId; + const auctionId = rtdUid || prebidAuctionId; + + const adgRtdSession = deepAccess(event.bidderRequests[0], 'ortb2.site.ext.data.adg_rtd.session', {}); const qp = { + org_id: adagioAdapter.options.organizationId, + site: adagioAdapter.options.site, v: 0, pbjsv: PREBID_VERSION, - org_id: params.organizationId, - site: params.site, - pv_id: params.pageviewId, + pv_id: _internal.getAdagioNs().pageviewId, auct_id: auctionId, adu_code: adUnitCode, url_dmn: w.location.hostname, - pgtyp: params.pagetype, - plcmt: params.placement, - t_n: params.testName || null, - t_v: params.testVersion || null, mts: mediaTypesKeys.join(','), ban_szs: bannerSizes.join(','), - bdrs: bidders.map(bidder => bidder.bidder).sort().join(','), - adg_mts: adagioMediaTypes.join(',') + bdrs: sortedBidderCodes.join(','), + pgtyp: deepAccess(event.bidderRequests[0], 'ortb2.site.ext.data.pagetype', null), + plcmt: deepAccess(adUnits[0], 'ortb2Imp.ext.data.placement', null), + t_n: adgRtdSession.testName || null, + t_v: adgRtdSession.testVersion || null, + s_id: adgRtdSession.id || null, + s_new: adgRtdSession.new || null, + bdrs_src: biddersSrc, }; + if (adagioBidRequest && adagioBidRequest.bids) { + const adagioAdUnitBids = adagioBidRequest.bids.filter(bid => bid.adUnitCode === adUnitCode); + if (adagioAdUnitBids.length > 0) { + // Get all media types requested for Adagio. + const adagioMediaTypes = removeDuplicates( + adagioAdUnitBids.map(bid => Object.keys(bid.mediaTypes)).flat(), + mediaTypeKey => mediaTypeKey + ).flat().map(mediaType => getMediaTypeAlias(mediaType)).sort(); + + qp.adg_mts = adagioMediaTypes.join(','); + // for backward compatibility: if we didn't find organizationId & site but we have a bid from adagio we might still find it in params + qp.org_id = qp.org_id || adagioAdUnitBids[0].params.organizationId; + qp.site = qp.site || adagioAdUnitBids[0].params.site; + } + } + cache.auctions[prebidAuctionId][adUnitCode] = qp; sendNewBeacon(prebidAuctionId, adUnitCode); }); @@ -306,13 +310,21 @@ function handlerAuctionEnd(event) { return bid ? getCurrencyData(bid).netCpm : null } + const perfNavigation = performance.getEntriesByType('navigation')[0]; + cache.updateAuction(auctionId, adUnitCode, { bdrs_bid: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidResponseMapper).join(','), - bdrs_cpm: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidCpmMapper).join(',') + bdrs_cpm: cache.getBiddersFromAuction(auctionId, adUnitCode).map(bidCpmMapper).join(','), + // check timings at the end of the auction to leave time to the browser to update it + dom_i: Math.round(perfNavigation['domInteractive']) || null, + dom_c: Math.round(perfNavigation['domComplete']) || null, + loa_e: Math.round(perfNavigation['loadEventEnd']) || null, }); + sendNewBeacon(auctionId, adUnitCode); }); } + function handlerBidWon(event) { let auctionId = getTargetedAuctionId(event); @@ -326,6 +338,9 @@ function handlerBidWon(event) { (event.latestTargetedAuctionId && event.latestTargetedAuctionId !== event.auctionId) ? cache.getAdagioAuctionId(event.auctionId) : null); + + const perfNavigation = performance.getEntriesByType('navigation')[0]; + cache.updateAuction(auctionId, event.adUnitCode, { win_bdr: event.bidder, win_mt: getMediaTypeAlias(event.mediaType), @@ -334,6 +349,11 @@ function handlerBidWon(event) { win_net_cpm: currencyData.netCpm, win_og_cpm: currencyData.orginalCpm, + // check timings at the end of the auction to leave time to the browser to update it + dom_i: Math.round(perfNavigation['domInteractive']) || null, + dom_c: Math.round(perfNavigation['domComplete']) || null, + loa_e: Math.round(perfNavigation['loadEventEnd']) || null, + // cache bid id auct_id_c: adagioAuctionCacheId, }); @@ -405,6 +425,24 @@ adagioAdapter.originEnableAnalytics = adagioAdapter.enableAnalytics; adagioAdapter.enableAnalytics = config => { _internal.getAdagioNs().versions.adagioAnalyticsAdapter = VERSION; + let modules = getGlobal().installedModules; + if (modules && (!modules.length || modules.indexOf('adagioRtdProvider') === -1 || modules.indexOf('rtdModule') === -1)) { + logError('Adagio Analytics Adapter requires rtdModule & adagioRtdProvider modules which are not installed. No beacon will be sent'); + return; + } + + adagioAdapter.options = config.options || {}; + if (!adagioAdapter.options.organizationId) { + logWarn('Adagio Analytics Adapter: organizationId is required and is missing will try to fallback on params.'); + } else { + adagioAdapter.options.organizationId = adagioAdapter.options.organizationId.toString(); // allows publisher to pass it as a number + } + if (!adagioAdapter.options.site) { + logWarn('Adagio Analytics Adapter: site is required and is missing will try to fallback on params.'); + } else if (typeof adagioAdapter.options.site !== 'string') { + logWarn('Adagio Analytics Adapter: site should be a string will try to fallback on params.'); + adagioAdapter.options.site = undefined; + } adagioAdapter.originEnableAnalytics(config); } diff --git a/modules/adagioAnalyticsAdapter.md b/modules/adagioAnalyticsAdapter.md index 9fc2cb0bb88..916f9ec9c58 100644 --- a/modules/adagioAnalyticsAdapter.md +++ b/modules/adagioAnalyticsAdapter.md @@ -13,5 +13,9 @@ Analytics adapter for Adagio ```js pbjs.enableAnalytics({ provider: 'adagio', + options: { + organizationId: '1000', // Required. Provided by Adagio + site: 'my-website', // Required. Provided by Adagio + } }); ``` diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 9737a8da65d..9bcebf9205e 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -20,11 +20,11 @@ import { import { getRefererInfo, parseDomain } from '../src/refererDetection.js'; import { OUTSTREAM } from '../src/video.js'; import { Renderer } from '../src/Renderer.js'; +import { _ADAGIO } from '../libraries/adagioUtils/adagioUtils.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { find } from '../src/polyfill.js'; import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js'; -import { _ADAGIO } from '../libraries/adagioUtils/adagioUtils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { userSync } from '../src/userSync.js'; @@ -176,17 +176,6 @@ function _getUspConsent(bidderRequest) { return (deepAccess(bidderRequest, 'uspConsent')) ? { uspConsent: bidderRequest.uspConsent } : false; } -function _getGppConsent(bidderRequest) { - let gpp = deepAccess(bidderRequest, 'gppConsent.gppString') - let gppSid = deepAccess(bidderRequest, 'gppConsent.applicableSections') - - if (!gpp || !gppSid) { - gpp = deepAccess(bidderRequest, 'ortb2.regs.gpp', '') - gppSid = deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []) - } - return { gpp, gppSid } -} - function _getSchain(bidRequest) { return deepAccess(bidRequest, 'schain'); } @@ -559,7 +548,7 @@ export const spec = { const gdprConsent = _getGdprConsent(bidderRequest) || {}; const uspConsent = _getUspConsent(bidderRequest) || {}; const coppa = _getCoppa(); - const gppConsent = _getGppConsent(bidderRequest) + const { gpp, gpp_sid: gppSid } = deepAccess(bidderRequest, 'ortb2.regs', {}); const schain = _getSchain(validBidRequests[0]); const eids = _getEids(validBidRequests[0]) || []; const syncEnabled = deepAccess(config.getConfig('userSync'), 'syncEnabled') @@ -747,8 +736,8 @@ export const spec = { gdpr: gdprConsent, coppa: coppa, ccpa: uspConsent, - gpp: gppConsent.gpp, - gppSid: gppConsent.gppSid, + gpp: gpp || '', + gppSid: gppSid || [], dsa: dsa // populated if exists }, schain: schain, diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js index 22f92941312..6926c69d453 100644 --- a/modules/connectIdSystem.js +++ b/modules/connectIdSystem.js @@ -318,9 +318,11 @@ export const connectIdSubmodule = { */ userHasOptedOut() { try { - // TODO FIX THIS RULES VIOLATION - // eslint-disable-next-line - return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; + if (storage.localStorageIsEnabled()) { + return storage.getDataFromLocalStorage(OVERRIDE_OPT_OUT_KEY) === '1'; + } else { + return true; + } } catch { return false; } diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 91d067ab67d..8429228d7af 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -48,7 +48,7 @@ const SUA_ATTRIBUTES = [ const CERBERUS = Object.freeze({ KEY: 'krg_crb', - SYNC_URL: 'https://crb.kargo.com/api/v1/initsyncrnd/{UUID}?seed={SEED}&idx={INDEX}&gdpr={GDPR}&gdpr_consent={GDPR_CONSENT}&us_privacy={US_PRIVACY}&gpp={GPP_STRING}&gpp_sid={GPP_SID}', + SYNC_URL: 'https://crb.kargo.com/api/v1/initsyncrnd/{UUID}?seed={SEED}&gdpr={GDPR}&gdpr_consent={GDPR_CONSENT}&us_privacy={US_PRIVACY}&gpp={GPP_STRING}&gpp_sid={GPP_SID}', SYNC_COUNT: 5, PAGE_VIEW_ID: 'pageViewId', PAGE_VIEW_TIMESTAMP: 'pageViewTimestamp', @@ -274,19 +274,16 @@ function getUserSyncs(syncOptions, _, gdprConsent, usPrivacy, gppConsent) { return syncs; } if (syncOptions.iframeEnabled && seed && clientId) { - for (let i = 0; i < CERBERUS.SYNC_COUNT; i++) { - syncs.push({ - type: 'iframe', - url: CERBERUS.SYNC_URL.replace('{UUID}', clientId) - .replace('{SEED}', seed) - .replace('{INDEX}', i) - .replace('{GDPR}', gdpr) - .replace('{GDPR_CONSENT}', gdprConsentString) - .replace('{US_PRIVACY}', usPrivacy || '') - .replace('{GPP_STRING}', gppString) - .replace('{GPP_SID}', gppApplicableSections) - }); - } + syncs.push({ + type: 'iframe', + url: CERBERUS.SYNC_URL.replace('{UUID}', clientId) + .replace('{SEED}', seed) + .replace('{GDPR}', gdpr) + .replace('{GDPR_CONSENT}', gdprConsentString) + .replace('{US_PRIVACY}', usPrivacy || '') + .replace('{GPP_STRING}', gppString) + .replace('{GPP_SID}', gppApplicableSections) + }) } return syncs; } diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index b4f7cf50ffe..29700c14a6c 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -125,7 +125,7 @@ const converter = ortbConverter({ deepSetValue(request, 'ext.localStorage.nexx360Id', nexx360LocalStorage.nexx360Id); } const amxId = getAmxId(); - if (amxId) deepSetValue(request, 'ext.localStorage.amxId', amxId()); + if (amxId) deepSetValue(request, 'ext.localStorage.amxId', amxId); deepSetValue(request, 'ext.version', '$prebid.version$'); deepSetValue(request, 'ext.source', 'prebid.js'); deepSetValue(request, 'ext.pageViewId', PAGE_VIEW_ID); diff --git a/src/prebid.js b/src/prebid.js index 2283f8487e8..e91af3e4d04 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -869,6 +869,10 @@ pbjsInstance.getHighestCpmBids = function (adUnitCode) { return targeting.getWinningBids(adUnitCode); }; +pbjsInstance.clearAllAuctions = function () { + auctionManager.clearAllAuctions(); +}; + if (FEATURES.VIDEO) { /** * Mark the winning bid as used, should only be used in conjunction with video diff --git a/test/spec/modules/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index ec3e2e1a28e..2c1f259ea35 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -16,11 +16,17 @@ describe('adagio analytics adapter - adagio.js', () => { sandbox = sinon.createSandbox(); sandbox.stub(events, 'getEvents').returns([]); + sandbox.stub(prebidGlobal, 'getGlobal').returns({ + installedModules: ['adagioRtdProvider', 'rtdModule'] + }); + adapterManager.registerAnalyticsAdapter({ code: 'adagio', adapter: adagioAnalyticsAdapter }); + _internal.getAdagioNs().pageviewId = 'a68e6d70-213b-496c-be0a-c468ff387106'; + adagioQueuePushSpy = sandbox.spy(_internal.getAdagioNs().queue, 'push'); }); @@ -32,7 +38,11 @@ describe('adagio analytics adapter - adagio.js', () => { describe('track', () => { beforeEach(() => { adapterManager.enableAnalytics({ - provider: 'adagio' + provider: 'adagio', + options: { + organizationId: '1001', + site: 'test-com', + } }); }); @@ -108,6 +118,7 @@ const AUCTION_ID = '25c6d7f5-699a-4bfc-87c9-996f915341fa'; const RTD_AUCTION_ID = '753b3784-12a1-44c2-9d08-d0e4ee910e69'; const RTD_AUCTION_ID_CACHE = '04d991be-8f7d-4491-930b-2b7eefb3c447'; const AUCTION_ID_CACHE = 'b43d24a0-13d4-406d-8176-3181402bafc4'; +const SESSION_ID = 'c4f9e517-a592-45af-9560-ca191823d591'; const BID_ADAGIO = { bidder: 'adagio', @@ -181,14 +192,7 @@ const BID_CACHED = Object.assign({}, BID_ADAGIO, { }); const PARAMS_ADG = { - organizationId: '1001', - site: 'test-com', - pageviewId: 'a68e6d70-213b-496c-be0a-c468ff387106', environment: 'desktop', - pagetype: 'article', - placement: 'pave_top', - testName: 'test', - testVersion: 'version', }; const ORTB_DATA = { @@ -197,6 +201,11 @@ const ORTB_DATA = { const ADG_RTD = { 'uid': RTD_AUCTION_ID, + 'session': { + 'testName': 'test', + 'testVersion': 'version', + 'id': SESSION_ID, + } }; const AUCTION_INIT_ANOTHER = { @@ -236,7 +245,14 @@ const AUCTION_INIT_ANOTHER = { ...PARAMS_ADG }, }, ], - 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014' + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'ortb2Imp': { + 'ext': { + 'data': { + 'placement': 'pave_top', + } + } + }, }, { 'code': '/19968336/footer-bid-tag-1', 'mediaTypes': { @@ -256,7 +272,14 @@ const AUCTION_INIT_ANOTHER = { 'publisherId': '1001' }, } ], - 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014' + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'ortb2Imp': { + 'ext': { + 'data': { + 'placement': 'pave_top', + } + } + }, } ], 'adUnitCodes': ['/19968336/header-bid-tag-1', '/19968336/footer-bid-tag-1'], 'bidderRequests': [ { @@ -414,7 +437,14 @@ const AUCTION_INIT_CACHE = { ...PARAMS_ADG }, }, ], - 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014' + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'ortb2Imp': { + 'ext': { + 'data': { + 'placement': 'pave_top', + } + } + }, }, { 'code': '/19968336/footer-bid-tag-1', 'mediaTypes': { @@ -434,7 +464,14 @@ const AUCTION_INIT_CACHE = { 'publisherId': '1001' }, } ], - 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014' + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'ortb2Imp': { + 'ext': { + 'data': { + 'placement': 'pave_top', + } + } + }, } ], 'adUnitCodes': ['/19968336/header-bid-tag-1', '/19968336/footer-bid-tag-1'], 'bidderRequests': [ { @@ -604,10 +641,27 @@ describe('adagio analytics adapter', () => { let sandbox; beforeEach(() => { - sandbox = sinon.sandbox.create(); + sandbox = sinon.createSandbox(); sandbox.stub(events, 'getEvents').returns([]); + sandbox.stub(prebidGlobal, 'getGlobal').returns({ + installedModules: ['adagioRtdProvider', 'rtdModule'], + convertCurrency: (cpm, from, to) => { + const convKeys = { + 'GBP-EUR': 0.7, + 'EUR-GBP': 1.3, + 'USD-EUR': 0.8, + 'EUR-USD': 1.2, + 'USD-GBP': 0.6, + 'GBP-USD': 1.6, + }; + return cpm * (convKeys[`${from}-${to}`] || 1); + } + }); + + _internal.getAdagioNs().pageviewId = 'a68e6d70-213b-496c-be0a-c468ff387106'; + adapterManager.registerAnalyticsAdapter({ code: 'adagio', adapter: adagioAnalyticsAdapter @@ -622,7 +676,11 @@ describe('adagio analytics adapter', () => { describe('track', () => { beforeEach(() => { adapterManager.enableAnalytics({ - provider: 'adagio' + provider: 'adagio', + options: { + organizationId: '1001', + site: 'test-com', + } }); }); @@ -631,20 +689,6 @@ describe('adagio analytics adapter', () => { }); it('builds and sends auction data', () => { - sandbox.stub(prebidGlobal, 'getGlobal').returns({ - convertCurrency: (cpm, from, to) => { - const convKeys = { - 'GBP-EUR': 0.7, - 'EUR-GBP': 1.3, - 'USD-EUR': 0.8, - 'EUR-USD': 1.2, - 'USD-GBP': 0.6, - 'GBP-USD': 1.6, - }; - return cpm * (convKeys[`${from}-${to}`] || 1); - } - }); - events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); @@ -652,7 +696,7 @@ describe('adagio analytics adapter', () => { events.emit(EVENTS.BID_WON, MOCK.BID_WON.another); events.emit(EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); - expect(server.requests.length).to.equal(3, 'requests count'); + 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'); @@ -660,6 +704,7 @@ describe('adagio analytics adapter', () => { expect(pathname).to.equal('/pba.gif'); expect(search.v).to.equal('1'); expect(search.pbjsv).to.equal('$prebid.version$'); + expect(search.s_id).to.equal(SESSION_ID); expect(search.auct_id).to.equal(RTD_AUCTION_ID); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); expect(search.org_id).to.equal('1001'); @@ -679,7 +724,16 @@ describe('adagio analytics adapter', () => { expect(protocol).to.equal('https'); expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); + expect(search.v).to.equal('1'); + } + + { + 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('2'); + expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); expect(search.e_sid).to.equal('42'); expect(search.e_pba_test).to.equal('true'); expect(search.bdrs_bid).to.equal('1,1,0'); @@ -687,7 +741,17 @@ describe('adagio analytics adapter', () => { } { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[2].url); + 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('2'); + expect(search.auct_id).to.equal(RTD_AUCTION_ID); + expect(search.adu_code).to.equal('/19968336/footer-bid-tag-1'); + } + + { + 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'); @@ -703,20 +767,6 @@ describe('adagio analytics adapter', () => { }); it('builds and sends auction data with a cached bid win', () => { - sandbox.stub(prebidGlobal, 'getGlobal').returns({ - convertCurrency: (cpm, from, to) => { - const convKeys = { - 'GBP-EUR': 0.7, - 'EUR-GBP': 1.3, - 'USD-EUR': 0.8, - 'EUR-USD': 1.2, - 'USD-GBP': 0.6, - 'GBP-USD': 1.6, - }; - return cpm * (convKeys[`${from}-${to}`] || 1); - } - }); - events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.bidcached); events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); @@ -725,7 +775,7 @@ describe('adagio analytics adapter', () => { events.emit(EVENTS.BID_WON, MOCK.BID_WON.bidcached); events.emit(EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED.bidcached); - expect(server.requests.length).to.equal(5, 'requests count'); + expect(server.requests.length).to.equal(8, 'requests count'); { // the first request is getting cached we expect to see its auction id later when it's re-used const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[0].url); @@ -735,6 +785,7 @@ describe('adagio analytics adapter', () => { expect(search.v).to.equal('1'); expect(search.pbjsv).to.equal('$prebid.version$'); expect(search.auct_id).to.equal(RTD_AUCTION_ID_CACHE); + expect(search.s_id).to.equal(SESSION_ID); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); expect(search.org_id).to.equal('1001'); expect(search.site).to.equal('test-com'); @@ -757,6 +808,27 @@ describe('adagio analytics adapter', () => { expect(pathname).to.equal('/pba.gif'); expect(search.v).to.equal('1'); expect(search.pbjsv).to.equal('$prebid.version$'); + expect(search.auct_id).to.equal(RTD_AUCTION_ID_CACHE); + expect(search.adu_code).to.equal('/19968336/footer-bid-tag-1'); + expect(search.org_id).to.equal('1001'); + 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.pgtyp).to.equal('article'); + expect(search.plcmt).to.equal('pave_top'); + expect(search.mts).to.equal('ban'); + expect(search.ban_szs).to.equal('640x480'); + expect(search.bdrs).to.equal('another'); + expect(search.adg_mts).to.not.exist; + } + + { + 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('1'); + expect(search.pbjsv).to.equal('$prebid.version$'); expect(search.auct_id).to.equal(RTD_AUCTION_ID); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); expect(search.org_id).to.equal('1001'); @@ -772,11 +844,24 @@ describe('adagio analytics adapter', () => { } { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[2].url); + 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('1'); + expect(search.auct_id).to.equal(RTD_AUCTION_ID); + expect(search.adu_code).to.equal('/19968336/footer-bid-tag-1'); + expect(search.pv_id).to.equal('a68e6d70-213b-496c-be0a-c468ff387106'); + } + + { + 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('2'); + expect(search.auct_id).to.equal(RTD_AUCTION_ID); + expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); expect(search.e_sid).to.equal('42'); expect(search.e_pba_test).to.equal('true'); expect(search.bdrs_bid).to.equal('0,0,0'); @@ -784,7 +869,18 @@ describe('adagio analytics adapter', () => { } { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[3].url); + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[5].url); + expect(protocol).to.equal('https'); + expect(hostname).to.equal('c.4dex.io'); + expect(pathname).to.equal('/pba.gif'); + expect(search.v).to.equal('2'); + expect(search.auct_id).to.equal(RTD_AUCTION_ID); + expect(search.adu_code).to.equal('/19968336/footer-bid-tag-1'); + expect(search.rndr).to.not.exist; + } + + { + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[6].url); expect(protocol).to.equal('https'); expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); @@ -801,7 +897,7 @@ describe('adagio analytics adapter', () => { } { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[4].url); + const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[7].url); expect(protocol).to.equal('https'); expect(hostname).to.equal('c.4dex.io'); expect(pathname).to.equal('/pba.gif'); @@ -809,12 +905,20 @@ describe('adagio analytics adapter', () => { expect(search.auct_id).to.equal(RTD_AUCTION_ID); expect(search.auct_id_c).to.equal(RTD_AUCTION_ID_CACHE); expect(search.adu_code).to.equal('/19968336/header-bid-tag-1'); + expect(search.win_bdr).to.equal('adagio'); + expect(search.win_mt).to.equal('ban'); + expect(search.win_ban_sz).to.equal('728x90'); + expect(search.win_net_cpm).to.equal('1.42'); + expect(search.win_og_cpm).to.equal('1.42'); expect(search.rndr).to.equal('0'); } }); it('send an "empty" cpm when adserver currency != USD and convertCurrency() is undefined', () => { - sandbox.stub(prebidGlobal, 'getGlobal').returns({}); + sandbox.restore(); + sandbox.stub(prebidGlobal, 'getGlobal').returns({ + installedModules: ['adagioRtdProvider', 'rtdModule'] + }); events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); @@ -823,14 +927,15 @@ describe('adagio analytics adapter', () => { events.emit(EVENTS.BID_WON, MOCK.BID_WON.another); events.emit(EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); - expect(server.requests.length).to.equal(3, 'requests count'); + expect(server.requests.length).to.equal(5, 'requests count'); // fail to compute bidder cpm and send an "empty" cpm { - const { protocol, hostname, pathname, search } = utils.parseUrl(server.requests[1].url); + 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.s_id).to.equal(SESSION_ID); expect(search.v).to.equal('2'); expect(search.e_sid).to.equal('42'); expect(search.e_pba_test).to.equal('true'); diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 7c1b3421970..629771de9d6 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -801,77 +801,24 @@ describe('Adagio bid adapter', () => { describe('with GPP', function() { const bid01 = new BidRequestBuilder().withParams().build(); - const regsGpp = 'regs_gpp_consent_string'; - const regsApplicableSections = [2]; + const gpp = 'gpp_consent_string'; + const gppSid = [1]; - const ortb2Gpp = 'ortb2_gpp_consent_string'; - const ortb2GppSid = [1]; - - context('When GPP in regs module', function() { - it('send gpp and gppSid to the server', function() { - const bidderRequest = new BidderRequestBuilder({ - gppConsent: { - gppString: regsGpp, - applicableSections: regsApplicableSections, - } - }).build(); - - const requests = spec.buildRequests([bid01], bidderRequest); - - expect(requests[0].data.regs.gpp).to.equal(regsGpp); - expect(requests[0].data.regs.gppSid).to.equal(regsApplicableSections); - }); - }); - - context('When GPP partially defined in regs module', function() { - it('send gpp and gppSid coming from ortb2 to the server', function() { - const bidderRequest = new BidderRequestBuilder({ - gppConsent: { - gppString: regsGpp, - }, - ortb2: { - regs: { - gpp: ortb2Gpp, - gpp_sid: ortb2GppSid, - } - } - }).build(); - - const requests = spec.buildRequests([bid01], bidderRequest); - - expect(requests[0].data.regs.gpp).to.equal(ortb2Gpp); - expect(requests[0].data.regs.gppSid).to.equal(ortb2GppSid); - }); - - it('send empty gpp and gppSid if no ortb2 fields to the server', function() { - const bidderRequest = new BidderRequestBuilder({ - gppConsent: { - gppString: regsGpp, - } - }).build(); - - const requests = spec.buildRequests([bid01], bidderRequest); - - expect(requests[0].data.regs.gpp).to.equal(''); - expect(requests[0].data.regs.gppSid).to.be.empty; - }); - }); - - context('When GPP defined in ortb2 module', function() { + context('When GPP is defined', function() { it('send gpp and gppSid coming from ortb2 to the server', function() { const bidderRequest = new BidderRequestBuilder({ ortb2: { regs: { - gpp: ortb2Gpp, - gpp_sid: ortb2GppSid, + gpp, + gpp_sid: gppSid, } } }).build(); const requests = spec.buildRequests([bid01], bidderRequest); - expect(requests[0].data.regs.gpp).to.equal(ortb2Gpp); - expect(requests[0].data.regs.gppSid).to.equal(ortb2GppSid); + expect(requests[0].data.regs.gpp).to.equal(gpp); + expect(requests[0].data.regs.gppSid).to.equal(gppSid); }); }); diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js index 686c3d63a63..3009ecef769 100644 --- a/test/spec/modules/connectIdSystem_spec.js +++ b/test/spec/modules/connectIdSystem_spec.js @@ -549,24 +549,28 @@ describe('Yahoo ConnectID Submodule', () => { expect(result.callback).to.be.a('function'); }); + function mockOptout(value) { + getLocalStorageStub.callsFake((key) => { + if (key === 'connectIdOptOut') return value; + }) + } + it('returns an undefined if the Yahoo specific opt-out key is present in local storage', () => { - localStorage.setItem('connectIdOptOut', '1'); + mockOptout('1'); expect(invokeGetIdAPI({ he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData)).to.be.undefined; - localStorage.removeItem('connectIdOptOut'); }); it('returns an object with the callback function if the correct params are passed and Yahoo opt-out value is not "1"', () => { - localStorage.setItem('connectIdOptOut', 'true'); + mockOptout('true'); let result = invokeGetIdAPI({ he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData); expect(result).to.be.an('object').that.has.all.keys('callback'); expect(result.callback).to.be.a('function'); - localStorage.removeItem('connectIdOptOut'); }); it('Makes an ajax GET request to the production API endpoint with pixelId and he query params', () => { @@ -804,6 +808,25 @@ describe('Yahoo ConnectID Submodule', () => { }); }); }); + describe('userHasOptedOut()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.userHasOptedOut).to.be.a('function'); + }); + + it('should return false when local storage key has not been set function', () => { + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); + + it('should return true when local storage key has been set to "1"', () => { + getLocalStorageStub.returns('1'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.true; + }); + + it('should return false when local storage key has not been set to "1"', () => { + getLocalStorageStub.returns('hello'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); + }); }); describe('decode()', () => { @@ -884,28 +907,4 @@ describe('Yahoo ConnectID Submodule', () => { })).to.be.true; }); }); - - describe('userHasOptedOut()', () => { - afterEach(() => { - localStorage.removeItem('connectIdOptOut'); - }); - - it('should return a function', () => { - expect(connectIdSubmodule.userHasOptedOut).to.be.a('function'); - }); - - it('should return false when local storage key has not been set function', () => { - expect(connectIdSubmodule.userHasOptedOut()).to.be.false; - }); - - it('should return true when local storage key has been set to "1"', () => { - localStorage.setItem('connectIdOptOut', '1'); - expect(connectIdSubmodule.userHasOptedOut()).to.be.true; - }); - - it('should return false when local storage key has not been set to "1"', () => { - localStorage.setItem('connectIdOptOut', 'hello'); - expect(connectIdSubmodule.userHasOptedOut()).to.be.false; - }); - }); }); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 590d98969c3..e24c34dd1ab 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1885,16 +1885,15 @@ describe('kargo adapter tests', function() { describe('getUserSyncs', function() { let crb = {}; const clientId = 'random-client-id-string'; - const baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid='; + const baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid='; - function buildSyncUrls(baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=') { + function buildSyncUrls(baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=') { let syncs = []; - for (let i = 0; i < 5; i++) { - syncs.push({ - type: 'iframe', - url: baseUrl.replace(/idx=\d+&/, `idx=${i}&`), - }); - } + + syncs.push({ + type: 'iframe', + url: baseUrl + }); return syncs; } diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 9bd71fb5a7a..de267b793b2 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -3757,4 +3757,15 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledOnce(adapterManager.callBidBillableBidder); }); }); + + describe('clearAllAuctions', () => { + after(() => { + resetAuction(); + }); + it('clears auction data', function () { + expect(auctionManager.getBidsReceived().length).to.not.equal(0); + $$PREBID_GLOBAL$$.clearAllAuctions(); + expect(auctionManager.getBidsReceived().length).to.equal(0); + }); + }); });