diff --git a/eslint.config.js b/eslint.config.js index 46d0eb86da4..2d14584063a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -209,6 +209,21 @@ module.exports = [ object: 'navigator', message: 'use ajax.js instead' }, + { + property: 'doNotTrack', + object: 'navigator', + message: 'DNT was deprecated by W3C; Prebid no longer supports DNT signals' + }, + { + property: 'msDoNotTrack', + object: 'navigator', + message: 'DNT was deprecated by W3C; Prebid no longer supports DNT signals' + }, + { + property: 'doNotTrack', + object: 'window', + message: 'DNT was deprecated by W3C; Prebid no longer supports DNT signals' + }, ...['outerText', 'innerText'].map(property => ({ property, message: 'use .textContent instead' diff --git a/integrationExamples/gpt/raveltechRtdProvider_example.html b/integrationExamples/gpt/raveltechRtdProvider_example.html index 8a0be63b6b8..4523ad17ec9 100644 --- a/integrationExamples/gpt/raveltechRtdProvider_example.html +++ b/integrationExamples/gpt/raveltechRtdProvider_example.html @@ -256,9 +256,6 @@ "expires": 28 } }, - { - "name": "quantcastId" - }, { "name": "criteo" }, diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index 3861037b401..618874f0bd5 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -234,9 +234,6 @@ "expires": 28 } }, - { - "name": "quantcastId" - }, { "name": "criteo" }, diff --git a/integrationExamples/longform/basic_w_bidderSettings.html b/integrationExamples/longform/basic_w_bidderSettings.html deleted file mode 100644 index fb87ea5d990..00000000000 --- a/integrationExamples/longform/basic_w_bidderSettings.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Test Page

-

requireExactDuration = false

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - \ No newline at end of file diff --git a/integrationExamples/longform/basic_w_custom_adserver_translation.html b/integrationExamples/longform/basic_w_custom_adserver_translation.html deleted file mode 100644 index 2dbb89506b5..00000000000 --- a/integrationExamples/longform/basic_w_custom_adserver_translation.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Integration Demo

-

custom adserver translation file

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - diff --git a/integrationExamples/longform/basic_w_priceGran.html b/integrationExamples/longform/basic_w_priceGran.html deleted file mode 100644 index 4ea9d5d19be..00000000000 --- a/integrationExamples/longform/basic_w_priceGran.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Test Page

-

requireExactDuration = false

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - \ No newline at end of file diff --git a/integrationExamples/longform/basic_w_requireExactDuration.html b/integrationExamples/longform/basic_w_requireExactDuration.html deleted file mode 100644 index 46b91887cfb..00000000000 --- a/integrationExamples/longform/basic_w_requireExactDuration.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Test Page

-

requireExactDuration = true

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - diff --git a/integrationExamples/longform/basic_wo_brandCategoryExclusion.html b/integrationExamples/longform/basic_wo_brandCategoryExclusion.html deleted file mode 100644 index 47ea4b7f47d..00000000000 --- a/integrationExamples/longform/basic_wo_brandCategoryExclusion.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Test Page

-

brandCategoryExclusion = false

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - diff --git a/integrationExamples/longform/basic_wo_requireExactDuration.html b/integrationExamples/longform/basic_wo_requireExactDuration.html deleted file mode 100644 index 6dbedbc6d39..00000000000 --- a/integrationExamples/longform/basic_wo_requireExactDuration.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Prebid Freewheel Integration Demo - - - - - - - - - - - - - - - - - - - -

Prebid Freewheel Test Page

-

requireExactDuration = false

-
-
- -
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-

- -

-
-
-
- // bids -
-
-
-
-
-
-
- - - - diff --git a/libraries/advangUtils/index.js b/libraries/advangUtils/index.js index 7d869cef9e1..18c8aead27a 100644 --- a/libraries/advangUtils/index.js +++ b/libraries/advangUtils/index.js @@ -1,6 +1,6 @@ import { generateUUID, isFn, parseSizesInput, parseUrl } from '../../src/utils.js'; -import { getDNT as getNavigatorDNT } from '../dnt/index.js'; import { config } from '../../src/config.js'; +import {getDNT} from '../dnt/index.js'; export const DEFAULT_MIMES = ['video/mp4', 'application/javascript']; @@ -46,10 +46,6 @@ export function isConnectedTV() { return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); } -export function getDoNotTrack(win = typeof window !== 'undefined' ? window : undefined) { - return getNavigatorDNT(win); -} - export function findAndFillParam(o, key, value) { try { if (typeof value === 'function') { @@ -145,7 +141,7 @@ export function createRequestData(bid, bidderRequest, isVideo, getBidParam, getS const o = { 'device': { 'langauge': (global.navigator.language).split('-')[0], - 'dnt': getDoNotTrack(global) ? 1 : 0, + 'dnt': getDNT() ? 1 : 0, 'devicetype': isMobile() ? 4 : isConnectedTV() ? 3 : 2, 'js': 1, 'os': getOsVersion() @@ -170,7 +166,7 @@ export function createRequestData(bid, bidderRequest, isVideo, getBidParam, getS o.site['ref'] = topReferrer; o.site['mobile'] = isMobile() ? 1 : 0; const secure = topLocation.protocol.indexOf('https') === 0 ? 1 : 0; - o.device['dnt'] = getDoNotTrack(global) ? 1 : 0; + o.device['dnt'] = getDNT() ? 1 : 0; findAndFillParam(o.site, 'name', function() { return global.top.document.title; diff --git a/libraries/categoryTranslationMapping/index.js b/libraries/categoryTranslationMapping/index.js deleted file mode 100644 index 13b10423450..00000000000 --- a/libraries/categoryTranslationMapping/index.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Provides mapping objects used by bidders for categoryTranslation type logic for Adpod feature - */ -export const APPNEXUS_CATEGORY_MAPPING = { - '1': 'IAB20-3', - '2': 'IAB18-5', - '3': 'IAB10-1', - '4': 'IAB2-3', - '5': 'IAB19-8', - '6': 'IAB22-1', - '7': 'IAB18-1', - '8': 'IAB12-3', - '9': 'IAB5-1', - '10': 'IAB4-5', - '11': 'IAB13-4', - '12': 'IAB8-7', - '13': 'IAB9-7', - '14': 'IAB7-1', - '15': 'IAB20-18', - '16': 'IAB10-7', - '17': 'IAB19-18', - '18': 'IAB13-6', - '19': 'IAB18-4', - '20': 'IAB1-5', - '21': 'IAB1-6', - '22': 'IAB3-4', - '23': 'IAB19-13', - '24': 'IAB22-2', - '25': 'IAB3-9', - '26': 'IAB17-18', - '27': 'IAB19-6', - '28': 'IAB1-7', - '29': 'IAB9-30', - '30': 'IAB20-7', - '31': 'IAB20-17', - '32': 'IAB7-32', - '33': 'IAB16-5', - '34': 'IAB19-34', - '35': 'IAB11-5', - '36': 'IAB12-3', - '37': 'IAB11-4', - '38': 'IAB12-3', - '39': 'IAB9-30', - '41': 'IAB7-44', - '42': 'IAB7-1', - '43': 'IAB7-30', - '50': 'IAB19-30', - '51': 'IAB17-12', - '52': 'IAB19-30', - '53': 'IAB3-1', - '55': 'IAB13-2', - '56': 'IAB19-30', - '57': 'IAB19-30', - '58': 'IAB7-39', - '59': 'IAB22-1', - '60': 'IAB7-39', - '61': 'IAB21-3', - '62': 'IAB5-1', - '63': 'IAB12-3', - '64': 'IAB20-18', - '65': 'IAB11-2', - '66': 'IAB17-18', - '67': 'IAB9-9', - '68': 'IAB9-5', - '69': 'IAB7-44', - '71': 'IAB22-3', - '73': 'IAB19-30', - '74': 'IAB8-5', - '78': 'IAB22-1', - '85': 'IAB12-2', - '86': 'IAB22-3', - '87': 'IAB11-3', - '112': 'IAB7-32', - '113': 'IAB7-32', - '114': 'IAB7-32', - '115': 'IAB7-32', - '118': 'IAB9-5', - '119': 'IAB9-5', - '120': 'IAB9-5', - '121': 'IAB9-5', - '122': 'IAB9-5', - '123': 'IAB9-5', - '124': 'IAB9-5', - '125': 'IAB9-5', - '126': 'IAB9-5', - '127': 'IAB22-1', - '132': 'IAB1-2', - '133': 'IAB19-30', - '137': 'IAB3-9', - '138': 'IAB19-3', - '140': 'IAB2-3', - '141': 'IAB2-1', - '142': 'IAB2-3', - '143': 'IAB17-13', - '166': 'IAB11-4', - '175': 'IAB3-1', - '176': 'IAB13-4', - '182': 'IAB8-9', - '183': 'IAB3-5' -}; diff --git a/libraries/dnt/index.js b/libraries/dnt/index.js index 1b03e848ca5..66aad467115 100644 --- a/libraries/dnt/index.js +++ b/libraries/dnt/index.js @@ -1,11 +1,7 @@ -function _getDNT(win) { - return win.navigator.doNotTrack === '1' || win.doNotTrack === '1' || win.navigator.msDoNotTrack === '1' || win.navigator.doNotTrack?.toLowerCase?.() === 'yes'; -} - -export function getDNT(win = window) { - try { - return _getDNT(win) || (win !== win.top && _getDNT(win.top)); - } catch (e) { - return false; - } +/** + * DNT was deprecated by W3C; Prebid no longer supports DNT signals. + * Keep this helper for backwards compatibility with adapters that still invoke getDNT(). + */ +export function getDNT() { + return false; } diff --git a/libraries/paapiTools/buyerOrigins.js b/libraries/paapiTools/buyerOrigins.js deleted file mode 100644 index ace9b7da073..00000000000 --- a/libraries/paapiTools/buyerOrigins.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - This list is several known buyer origins for PAAPI auctions. - Bidders should add anyone they like to it. - It is not intended to be comphensive nor maintained by the Core team. - Rather, Bid adapters should simply append additional constants whenever - the need arises in their adapter. - - The goal is to reduce expression of common constants over many - bid adapters attempting to define interestGroupBuyers - in advance of network traffic. - - Bidders should consider updating their interstGroupBuyer list - with server communication for auctions initiated after the first bid response. - - Known buyers without current importers are commented out. If you need one, uncomment it. -*/ - -export const BO_CSR_ONET = 'https://csr.onet.pl'; -// export const BO_DOUBLECLICK_GOOGLEADS = 'https://googleads.g.doubleclick.net'; -// export const BO_DOUBLECLICK_TD = 'https://td.doubleclick.net'; -// export const BO_RTBHOUSE = 'https://f.creativecdn.com'; -// export const BO_CRITEO_US = 'https://fledge.us.criteo.com'; -// export const BO_CRITEO_EU = 'https://fledge.eu.criteo.com'; -// export const BO_CRITEO_AS = 'https://fledge.as.criteo.com'; -// export const BO_CRITEO_GRID_MERCURY = 'https://grid-mercury.criteo.com'; -// export const BO_CRITEO_BIDSWITCH_TRADR = 'https://tradr.bsw-sb.criteo.com'; -// export const BO_CRITEO_BIDSWITCH_SANDBOX = 'https://dsp-paapi-sandbox.bsw-ig.criteo.com'; -// export const BO_APPSPOT = 'https://fledge-buyer-testing-1.uc.r.appspot.com'; -// export const BO_OPTABLE = 'https://ads.optable.co'; -// export const BO_ADROLL = 'https://x.adroll.com'; -// export const BO_ADFORM = 'https://a2.adform.net'; -// export const BO_RETARGETLY = 'https://cookieless-campaign.prd-00.retargetly.com'; -// export const BO_AUDIGENT = 'https://proton.ad.gt'; -// export const BO_YAHOO = 'https://pa.ybp.yahoo.com'; -// export const BO_DOTOMI = 'https://usadmm.dotomi.com'; diff --git a/libraries/riseUtils/index.js b/libraries/riseUtils/index.js index 77ca87f0fca..aefba4b2014 100644 --- a/libraries/riseUtils/index.js +++ b/libraries/riseUtils/index.js @@ -12,10 +12,10 @@ import { } from '../../src/utils.js'; import {BANNER, NATIVE, VIDEO} from '../../src/mediaTypes.js'; import {config} from '../../src/config.js'; -import { getDNT } from '../dnt/index.js'; import {ADAPTER_VERSION, DEFAULT_CURRENCY, DEFAULT_TTL, SUPPORTED_AD_TYPES} from './constants.js'; import {getGlobalVarName} from '../../src/buildOptions.js'; +import {getDNT} from '../dnt/index.js'; export const makeBaseSpec = (baseUrl, modes) => { return { diff --git a/libraries/vidazooUtils/bidderUtils.js b/libraries/vidazooUtils/bidderUtils.js index fa2cea1b6fa..98da155ed10 100644 --- a/libraries/vidazooUtils/bidderUtils.js +++ b/libraries/vidazooUtils/bidderUtils.js @@ -339,13 +339,6 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder data.gppSid = bidderRequest.ortb2.regs.gpp_sid; } - if (bidderRequest.paapi?.enabled) { - const fledge = bidderRequest?.ortb2Imp?.ext?.ae; - if (fledge) { - data.fledge = fledge; - } - } - const api = mediaTypes?.video?.api || []; if (api.includes(7)) { const sourceExt = bidderRequest?.ortb2?.source?.ext; diff --git a/metadata/disclosures/prebid/categoryTranslation.json b/metadata/disclosures/prebid/categoryTranslation.json deleted file mode 100644 index 82934ef440e..00000000000 --- a/metadata/disclosures/prebid/categoryTranslation.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "disclosures": [ - { - "identifier": "iabToFwMappingkey", - "type": "web", - "domains": ["*"], - "purposes": [ - 1 - ] - }, - { - "identifier": "iabToFwMappingkeyPub", - "type": "web", - "domains": ["*"], - "purposes": [ - 1 - ] - } - ], - "domains": [ - { - "domain": "*", - "use": "Category translation mappings are cached in localStorage" - } - ] -} diff --git a/metadata/modules.json b/metadata/modules.json index ff1fde0e0d3..3db59398215 100644 --- a/metadata/modules.json +++ b/metadata/modules.json @@ -5811,13 +5811,6 @@ "disclosureURL": null, "aliasOf": null }, - { - "componentType": "userId", - "componentName": "quantcastId", - "gvlid": "11", - "disclosureURL": null, - "aliasOf": null - }, { "componentType": "userId", "componentName": "rewardedInterestId", @@ -6225,4 +6218,4 @@ "gvlid": null } ] -} \ No newline at end of file +} diff --git a/metadata/modules/categoryTranslation.json b/metadata/modules/categoryTranslation.json deleted file mode 100644 index d1aa7a19217..00000000000 --- a/metadata/modules/categoryTranslation.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", - "disclosures": { - "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/categoryTranslation.json": { - "timestamp": "2026-02-06T14:30:25.253Z", - "disclosures": [ - { - "identifier": "iabToFwMappingkey", - "type": "web", - "purposes": [ - 1 - ] - }, - { - "identifier": "iabToFwMappingkeyPub", - "type": "web", - "purposes": [ - 1 - ] - } - ] - } - }, - "components": [ - { - "componentType": "prebid", - "componentName": "categoryTranslation", - "disclosureURL": "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/categoryTranslation.json" - } - ] -} \ No newline at end of file diff --git a/metadata/modules/quantcastBidAdapter.json b/metadata/modules/quantcastBidAdapter.json index 69c0e462a27..ddac251a1ba 100644 --- a/metadata/modules/quantcastBidAdapter.json +++ b/metadata/modules/quantcastBidAdapter.json @@ -48,4 +48,4 @@ "disclosureURL": "https://www.quantcast.com/.well-known/devicestorage.json" } ] -} \ No newline at end of file +} diff --git a/metadata/modules/ringieraxelspringerBidAdapter.json b/metadata/modules/ringieraxelspringerBidAdapter.json deleted file mode 100644 index 1ca1c72523f..00000000000 --- a/metadata/modules/ringieraxelspringerBidAdapter.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", - "disclosures": {}, - "components": [ - { - "componentType": "bidder", - "componentName": "das", - "aliasOf": null, - "gvlid": null, - "disclosureURL": null - }, - { - "componentType": "bidder", - "componentName": "ringieraxelspringer", - "aliasOf": "das", - "gvlid": null, - "disclosureURL": null - } - ] -} \ No newline at end of file diff --git a/metadata/overrides.mjs b/metadata/overrides.mjs index 214f778485c..869069f94d3 100644 --- a/metadata/overrides.mjs +++ b/metadata/overrides.mjs @@ -16,6 +16,5 @@ export default { operaadsIdSystem: 'operaId', relevadRtdProvider: 'RelevadRTDModule', sirdataRtdProvider: 'SirdataRTDModule', - fanBidAdapter: 'freedomadnetwork', - ringieraxelspringerBidAdapter: 'das' + fanBidAdapter: 'freedomadnetwork' } diff --git a/modules/.submodules.json b/modules/.submodules.json index c6b0db32e78..50416bf3c4c 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -50,7 +50,6 @@ "pubProvidedIdSystem", "publinkIdSystem", "pubmaticIdSystem", - "quantcastIdSystem", "rewardedInterestIdSystem", "sharedIdSystem", "taboolaIdSystem", @@ -65,10 +64,6 @@ "yandexIdSystem", "zeotapIdPlusIdSystem" ], - "adpod": [ - "freeWheelAdserverVideo", - "gamAdpod" - ], "rtdModule": [ "1plusXRtdProvider", "51DegreesRtdProvider", @@ -143,10 +138,6 @@ "jwplayerVideoProvider", "videojsVideoProvider", "adplayerproVideoProvider" - ], - "paapi": [ - "paapiForGpt", - "topLevelPaapi" ] } } diff --git a/modules/33acrossAnalyticsAdapter.js b/modules/33acrossAnalyticsAdapter.js index ad9b33d6762..6ee02b09d8c 100644 --- a/modules/33acrossAnalyticsAdapter.js +++ b/modules/33acrossAnalyticsAdapter.js @@ -401,8 +401,7 @@ function analyticEventHandler({ eventType, args }) { case EVENTS.BID_REJECTED: onBidRejected(args); break; - case EVENTS.NO_BID: - case EVENTS.SEAT_NON_BID: + case EVENTS.NO_BID: // todo: need to also consider pbsanalytics where nonbid is not null setCachedBidStatus(args.auctionId, args.bidId, BidStatus.NOBID); break; case EVENTS.BIDDER_ERROR: diff --git a/modules/AsteriobidPbmAnalyticsAdapter.js b/modules/AsteriobidPbmAnalyticsAdapter.js index 3783f6c3765..2a914824a94 100644 --- a/modules/AsteriobidPbmAnalyticsAdapter.js +++ b/modules/AsteriobidPbmAnalyticsAdapter.js @@ -231,9 +231,6 @@ function handleEvent(eventType, eventArgs) { case EVENTS.REQUEST_BIDS: { break; } - case EVENTS.ADD_AD_UNITS: { - break; - } case EVENTS.AD_RENDER_FAILED: { pmEvent.bid = eventArgs.bid; pmEvent.message = eventArgs.message; diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index 81fa3501ea0..9092946d3c1 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { _each, contains, @@ -20,7 +19,7 @@ import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; -import {getBidFloor} from '../libraries/adkernelUtils/adkernelUtils.js' +import {getBidFloor} from '../libraries/adkernelUtils/adkernelUtils.js'; /** * In case you're AdKernel whitelable platform's client who needs branded adapter to @@ -416,9 +415,6 @@ function makeDevice(fpd) { 'js': 1, 'language': getLanguage() }, fpd.device || {}); - if (getDNT()) { - device.dnt = 1; - } return {device: device}; } diff --git a/modules/adoceanBidAdapter.js b/modules/adoceanBidAdapter.js index 410b3c92338..e6b89272bc7 100644 --- a/modules/adoceanBidAdapter.js +++ b/modules/adoceanBidAdapter.js @@ -54,17 +54,6 @@ function buildRequest(bid, gdprConsent) { } payload.spots = 1; } - if (bid.mediaTypes.video.context === 'adpod') { - const durationRangeSec = bid.mediaTypes.video.durationRangeSec; - if (!bid.mediaTypes.video.adPodDurationSec || !isArray(durationRangeSec) || durationRangeSec.length === 0) { - return; - } - const spots = calculateAdPodSpotsNumber(bid.mediaTypes.video.adPodDurationSec, bid.mediaTypes.video.durationRangeSec); - const maxDuration = Math.max(...durationRangeSec); - payload.dur = bid.mediaTypes.video.adPodDurationSec; - payload.maxdur = maxDuration; - payload.spots = spots; - } } else if (bid.mediaTypes.banner) { payload.aosize = parseSizesInput(bid.mediaTypes.banner.sizes).join(','); } @@ -77,12 +66,6 @@ function buildRequest(bid, gdprConsent) { }; } -function calculateAdPodSpotsNumber(adPodDurationSec, durationRangeSec) { - const minAllowedDuration = Math.min(...durationRangeSec); - const numberOfSpots = Math.floor(adPodDurationSec / minAllowedDuration); - return numberOfSpots; -} - function interpretResponse(placementResponse, bidRequest, bids) { const requestId = bidRequest.bidIdMap[placementResponse.id]; if (!placementResponse.error && requestId) { @@ -134,9 +117,6 @@ export const spec = { if (bid.mediaTypes.video.context === 'instream') { return true; } - if (bid.mediaTypes.video.context === 'adpod') { - return !bid.mediaTypes.video.requireExactDuration; - } } return false; }, diff --git a/modules/adpod.js b/modules/adpod.js deleted file mode 100644 index 3d82c91e42e..00000000000 --- a/modules/adpod.js +++ /dev/null @@ -1,657 +0,0 @@ -/** - * This module houses the functionality to evaluate and process adpod adunits/bids. Specifically there are several hooked functions, - * that either supplement the base function (ie to check something additional or unique to adpod objects) or to replace the base function - * entirely when appropriate. - * - * Brief outline of each hook: - * - `callPrebidCacheHook` - for any adpod bids, this function will temporarily hold them in a queue in order to send the bids to Prebid Cache in bulk - * - `checkAdUnitSetupHook` - evaluates the adUnits to ensure that required fields for adpod adUnits are present. Invalid adpod adUntis are removed from the array. - * - `checkVideoBidSetupHook` - evaluates the adpod bid returned from an adaptor/bidder to ensure required fields are populated; also initializes duration bucket field. - * - * To initialize the module, there is an `initAdpodHooks()` function that should be imported and executed by a corresponding `...AdServerVideo` - * module that designed to support adpod video type ads. This import process allows this module to effectively act as a sub-module. - */ - -import { - deepAccess, - generateUUID, - groupBy, - isArray, - isArrayOfNums, - isNumber, - isPlainObject, - logError, - logInfo, - logWarn -} from '../src/utils.js'; -import { - addBidToAuction, - AUCTION_IN_PROGRESS, - getPriceByGranularity, - getPriceGranularity -} from '../src/auction.js'; -import {checkAdUnitSetup} from '../src/prebid.js'; -import {checkVideoBidSetup} from '../src/video.js'; -import {getHook, module, setupBeforeHookFnOnce} from '../src/hook.js'; -import {store} from '../src/videoCache.js'; -import {config} from '../src/config.js'; -import {ADPOD} from '../src/mediaTypes.js'; -import {auctionManager} from '../src/auctionManager.js'; -import { TARGETING_KEYS } from '../src/constants.js'; - -const TARGETING_KEY_PB_CAT_DUR = 'hb_pb_cat_dur'; -const TARGETING_KEY_CACHE_ID = 'hb_cache_id'; - -let queueTimeDelay = 50; -let queueSizeLimit = 5; -const bidCacheRegistry = createBidCacheRegistry(); - -/** - * Create a registry object that stores/manages bids while be held in queue for Prebid Cache. - * @returns registry object with defined accessor functions - */ -function createBidCacheRegistry() { - const registry = {}; - - function setupRegistrySlot(auctionId) { - registry[auctionId] = {}; - registry[auctionId].bidStorage = new Set(); - registry[auctionId].queueDispatcher = createDispatcher(queueTimeDelay); - registry[auctionId].initialCacheKey = generateUUID(); - } - - return { - addBid: function (bid) { - // create parent level object based on auction ID (in case there are concurrent auctions running) to store objects for that auction - if (!registry[bid.auctionId]) { - setupRegistrySlot(bid.auctionId); - } - registry[bid.auctionId].bidStorage.add(bid); - }, - removeBid: function (bid) { - registry[bid.auctionId].bidStorage.delete(bid); - }, - getBids: function (bid) { - return registry[bid.auctionId] && registry[bid.auctionId].bidStorage.values(); - }, - getQueueDispatcher: function (bid) { - return registry[bid.auctionId] && registry[bid.auctionId].queueDispatcher; - }, - setupInitialCacheKey: function (bid) { - if (!registry[bid.auctionId]) { - registry[bid.auctionId] = {}; - registry[bid.auctionId].initialCacheKey = generateUUID(); - } - }, - getInitialCacheKey: function (bid) { - return registry[bid.auctionId] && registry[bid.auctionId].initialCacheKey; - } - } -} - -/** - * Creates a function that when called updates the bid queue and extends the running timer (when called subsequently). - * Once the time threshold for the queue (defined by queueSizeLimit) is reached, the queue will be flushed by calling the `firePrebidCacheCall` function. - * If there is a long enough time between calls (based on timeoutDration), the queue will automatically flush itself. - * @param {Number} timeoutDuration number of milliseconds to pass before timer expires and current bid queue is flushed - * @returns {Function} - */ -function createDispatcher(timeoutDuration) { - let timeout; - let counter = 1; - - return function (auctionInstance, bidListArr, afterBidAdded, killQueue) { - const context = this; - - var callbackFn = function () { - firePrebidCacheCall.call(context, auctionInstance, bidListArr, afterBidAdded); - }; - - clearTimeout(timeout); - - if (!killQueue) { - // want to fire off the queue if either: size limit is reached or time has passed since last call to dispatcher - if (counter === queueSizeLimit) { - counter = 1; - callbackFn(); - } else { - counter++; - timeout = setTimeout(callbackFn, timeoutDuration); - } - } else { - counter = 1; - } - }; -} - -function getPricePartForAdpodKey(bid) { - let pricePart - const prioritizeDeals = config.getConfig('adpod.prioritizeDeals'); - if (prioritizeDeals && deepAccess(bid, 'video.dealTier')) { - const adpodDealPrefix = config.getConfig(`adpod.dealTier.${bid.bidderCode}.prefix`); - pricePart = (adpodDealPrefix) ? adpodDealPrefix + deepAccess(bid, 'video.dealTier') : deepAccess(bid, 'video.dealTier'); - } else { - const granularity = getPriceGranularity(bid); - pricePart = getPriceByGranularity(granularity)(bid); - } - return pricePart -} - -/** - * This function reads certain fields from the bid to generate a specific key used for caching the bid in Prebid Cache - * @param {Object} bid bid object to update - * @param {Boolean} brandCategoryExclusion value read from setConfig; influences whether category is required or not - */ -function attachPriceIndustryDurationKeyToBid(bid, brandCategoryExclusion) { - const initialCacheKey = bidCacheRegistry.getInitialCacheKey(bid); - const duration = deepAccess(bid, 'video.durationBucket'); - const pricePart = getPricePartForAdpodKey(bid); - let pcd; - - if (brandCategoryExclusion) { - const category = deepAccess(bid, 'meta.adServerCatId'); - pcd = `${pricePart}_${category}_${duration}s`; - } else { - pcd = `${pricePart}_${duration}s`; - } - - if (!bid.adserverTargeting) { - bid.adserverTargeting = {}; - } - bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] = pcd; - bid.adserverTargeting[TARGETING_KEY_CACHE_ID] = initialCacheKey; - bid.videoCacheKey = initialCacheKey; - bid.customCacheKey = `${pcd}_${initialCacheKey}`; -} - -/** - * Updates the running queue for the associated auction. - * Does a check to ensure the auction is still running; if it's not - the previously running queue is killed. - * @param {*} auctionInstance running context of the auction - * @param {Object} bidResponse bid object being added to queue - * @param {Function} afterBidAdded callback function used when Prebid Cache responds - */ -function updateBidQueue(auctionInstance, bidResponse, afterBidAdded) { - const bidListIter = bidCacheRegistry.getBids(bidResponse); - - if (bidListIter) { - const bidListArr = Array.from(bidListIter); - const callDispatcher = bidCacheRegistry.getQueueDispatcher(bidResponse); - const killQueue = !!(auctionInstance.getAuctionStatus() !== AUCTION_IN_PROGRESS); - callDispatcher(auctionInstance, bidListArr, afterBidAdded, killQueue); - } else { - logWarn('Attempted to cache a bid from an unknown auction. Bid:', bidResponse); - } -} - -/** - * Small helper function to remove bids from internal storage; normally b/c they're about to sent to Prebid Cache for processing. - * @param {Array[Object]} bidResponses list of bids to remove - */ -function removeBidsFromStorage(bidResponses) { - for (let i = 0; i < bidResponses.length; i++) { - bidCacheRegistry.removeBid(bidResponses[i]); - } -} - -/** - * This function will send a list of bids to Prebid Cache. It also removes the same bids from the internal bidCacheRegistry - * to maintain which bids are in queue. - * If the bids are successfully cached, they will be added to the respective auction. - * @param {*} auctionInstance running context of the auction - * @param {Array[Object]} bidList list of bid objects that need to be sent to Prebid Cache - * @param {Function} afterBidAdded callback function used when Prebid Cache responds - */ -function firePrebidCacheCall(auctionInstance, bidList, afterBidAdded) { - // remove entries now so other incoming bids won't accidentally have a stale version of the list while PBC is processing the current submitted list - removeBidsFromStorage(bidList); - - store(bidList, function (error, cacheIds) { - if (error) { - logWarn(`Failed to save to the video cache: ${error}. Video bid(s) must be discarded.`); - } else { - for (let i = 0; i < cacheIds.length; i++) { - // when uuid in response is empty string then the key already existed, so this bid wasn't cached - if (cacheIds[i].uuid !== '') { - addBidToAuction(auctionInstance, bidList[i]); - } else { - logInfo(`Detected a bid was not cached because the custom key was already registered. Attempted to use key: ${bidList[i].customCacheKey}. Bid was: `, bidList[i]); - } - afterBidAdded(); - } - } - }); -} - -/** - * This is the main hook function to handle adpod bids; maintains the logic to temporarily hold bids in a queue in order to send bulk requests to Prebid Cache. - * @param {Function} fn reference to original function (used by hook logic) - * @param {*} auctionInstance running context of the auction - * @param {Object} bidResponse incoming bid; if adpod, will be processed through hook function. If not adpod, returns to original function. - * @param {Function} afterBidAdded callback function used when Prebid Cache responds - * @param {Object} videoConfig mediaTypes.video from the bid's adUnit - */ -export function callPrebidCacheHook(fn, auctionInstance, bidResponse, afterBidAdded, videoConfig) { - if (videoConfig && videoConfig.context === ADPOD) { - const brandCategoryExclusion = config.getConfig('adpod.brandCategoryExclusion'); - const adServerCatId = deepAccess(bidResponse, 'meta.adServerCatId'); - if (!adServerCatId && brandCategoryExclusion) { - logWarn('Detected a bid without meta.adServerCatId while setConfig({adpod.brandCategoryExclusion}) was enabled. This bid has been rejected:', bidResponse); - afterBidAdded(); - } else { - if (config.getConfig('adpod.deferCaching') === false) { - bidCacheRegistry.addBid(bidResponse); - attachPriceIndustryDurationKeyToBid(bidResponse, brandCategoryExclusion); - - updateBidQueue(auctionInstance, bidResponse, afterBidAdded); - } else { - // generate targeting keys for bid - bidCacheRegistry.setupInitialCacheKey(bidResponse); - attachPriceIndustryDurationKeyToBid(bidResponse, brandCategoryExclusion); - - // add bid to auction - addBidToAuction(auctionInstance, bidResponse); - afterBidAdded(); - } - } - } else { - fn.call(this, auctionInstance, bidResponse, afterBidAdded, videoConfig); - } -} - -/** - * This hook function will review the adUnit setup and verify certain required values are present in any adpod adUnits. - * If the fields are missing or incorrectly setup, the adUnit is removed from the list. - * @param {Function} fn reference to original function (used by hook logic) - * @param {Array[Object]} adUnits list of adUnits to be evaluated - * @returns {Array[Object]} list of adUnits that passed the check - */ -export function checkAdUnitSetupHook(fn, adUnits) { - const goodAdUnits = adUnits.filter(adUnit => { - const mediaTypes = deepAccess(adUnit, 'mediaTypes'); - const videoConfig = deepAccess(mediaTypes, 'video'); - if (videoConfig && videoConfig.context === ADPOD) { - // run check to see if other mediaTypes are defined (ie multi-format); reject adUnit if so - if (Object.keys(mediaTypes).length > 1) { - logWarn(`Detected more than one mediaType in adUnitCode: ${adUnit.code} while attempting to define an 'adpod' video adUnit. 'adpod' adUnits cannot be mixed with other mediaTypes. This adUnit will be removed from the auction.`); - return false; - } - - let errMsg = `Detected missing or incorrectly setup fields for an adpod adUnit. Please review the following fields of adUnitCode: ${adUnit.code}. This adUnit will be removed from the auction.`; - - const playerSize = !!( - ( - videoConfig.playerSize && ( - isArrayOfNums(videoConfig.playerSize, 2) || ( - isArray(videoConfig.playerSize) && videoConfig.playerSize.every(sz => isArrayOfNums(sz, 2)) - ) - ) - ) || (videoConfig.sizeConfig) - ); - const adPodDurationSec = !!(videoConfig.adPodDurationSec && isNumber(videoConfig.adPodDurationSec) && videoConfig.adPodDurationSec > 0); - const durationRangeSec = !!(videoConfig.durationRangeSec && isArrayOfNums(videoConfig.durationRangeSec) && videoConfig.durationRangeSec.every(range => range > 0)); - - if (!playerSize || !adPodDurationSec || !durationRangeSec) { - errMsg += (!playerSize) ? '\nmediaTypes.video.playerSize' : ''; - errMsg += (!adPodDurationSec) ? '\nmediaTypes.video.adPodDurationSec' : ''; - errMsg += (!durationRangeSec) ? '\nmediaTypes.video.durationRangeSec' : ''; - logWarn(errMsg); - return false; - } - } - return true; - }); - adUnits = goodAdUnits; - fn.call(this, adUnits); -} - -/** - * This check evaluates the incoming bid's `video.durationSeconds` field and tests it against specific logic depending on adUnit config. Summary of logic below: - * when adUnit.mediaTypes.video.requireExactDuration is true - * - only bids that exactly match those listed values are accepted (don't round at all). - * - populate the `bid.video.durationBucket` field with the matching duration value - * when adUnit.mediaTypes.video.requireExactDuration is false - * - round the duration to the next highest specified duration value based on adunit. If the duration is above a range within a set buffer, that bid falls down into that bucket. - * (eg if range was [5, 15, 30] -> 2s is rounded to 5s; 17s is rounded back to 15s; 18s is rounded up to 30s) - * - if the bid is above the range of the listed durations (and outside the buffer), reject the bid - * - set the rounded duration value in the `bid.video.durationBucket` field for accepted bids - * @param {Object} videoMediaType 'mediaTypes.video' associated to bidResponse - * @param {Object} bidResponse incoming bidResponse being evaluated by bidderFactory - * @returns {boolean} return false if bid duration is deemed invalid as per adUnit configuration; return true if fine - */ -function checkBidDuration(videoMediaType, bidResponse) { - const buffer = 2; - const bidDuration = deepAccess(bidResponse, 'video.durationSeconds'); - const adUnitRanges = videoMediaType.durationRangeSec; - adUnitRanges.sort((a, b) => a - b); // ensure the ranges are sorted in numeric order - - if (!videoMediaType.requireExactDuration) { - const max = Math.max(...adUnitRanges); - if (bidDuration <= (max + buffer)) { - const nextHighestRange = ((adUnitRanges) || []).find(range => (range + buffer) >= bidDuration); - bidResponse.video.durationBucket = nextHighestRange; - } else { - logWarn(`Detected a bid with a duration value outside the accepted ranges specified in adUnit.mediaTypes.video.durationRangeSec. Rejecting bid: `, bidResponse); - return false; - } - } else { - if (((adUnitRanges) || []).find(range => range === bidDuration)) { - bidResponse.video.durationBucket = bidDuration; - } else { - logWarn(`Detected a bid with a duration value not part of the list of accepted ranges specified in adUnit.mediaTypes.video.durationRangeSec. Exact match durations must be used for this adUnit. Rejecting bid: `, bidResponse); - return false; - } - } - return true; -} - -/** - * This hooked function evaluates an adpod bid and determines if the required fields are present. - * If it's found to not be an adpod bid, it will return to original function via hook logic - * @param {Function} fn reference to original function (used by hook logic) - * @param {Object} bid incoming bid object - * @param {Object} adUnit adUnit object of associated bid - * @param {Object} videoMediaType copy of the `bidRequest.mediaTypes.video` object; used in original function - * @param {String} context value of the `bidRequest.mediaTypes.video.context` field; used in original function - * @returns {boolean} this return is only used for adpod bids - */ -export function checkVideoBidSetupHook(fn, bid, adUnit, videoMediaType, context) { - if (context === ADPOD) { - let result = true; - const brandCategoryExclusion = config.getConfig('adpod.brandCategoryExclusion'); - if (brandCategoryExclusion && !deepAccess(bid, 'meta.primaryCatId')) { - result = false; - } - - if (deepAccess(bid, 'video')) { - if (!deepAccess(bid, 'video.context') || bid.video.context !== ADPOD) { - result = false; - } - - if (!deepAccess(bid, 'video.durationSeconds') || bid.video.durationSeconds <= 0) { - result = false; - } else { - const isBidGood = checkBidDuration(videoMediaType, bid); - if (!isBidGood) result = false; - } - } - - if (!config.getConfig('cache.url') && bid.vastXml && !bid.vastUrl) { - logError(` - This bid contains only vastXml and will not work when a prebid cache url is not specified. - Try enabling prebid cache with pbjs.setConfig({ cache: {url: "..."} }); - `); - result = false; - }; - - fn.bail(result); - } else { - fn.call(this, bid, adUnit, videoMediaType, context); - } -} - -/** - * This function reads the (optional) settings for the adpod as set from the setConfig() - * @param {Object} config contains the config settings for adpod module - */ -export function adpodSetConfig(config) { - if (config.bidQueueTimeDelay !== undefined) { - if (typeof config.bidQueueTimeDelay === 'number' && config.bidQueueTimeDelay > 0) { - queueTimeDelay = config.bidQueueTimeDelay; - } else { - logWarn(`Detected invalid value for adpod.bidQueueTimeDelay in setConfig; must be a positive number. Using default: ${queueTimeDelay}`) - } - } - - if (config.bidQueueSizeLimit !== undefined) { - if (typeof config.bidQueueSizeLimit === 'number' && config.bidQueueSizeLimit > 0) { - queueSizeLimit = config.bidQueueSizeLimit; - } else { - logWarn(`Detected invalid value for adpod.bidQueueSizeLimit in setConfig; must be a positive number. Using default: ${queueSizeLimit}`) - } - } -} -config.getConfig('adpod', config => adpodSetConfig(config.adpod)); - -/** - * This function initializes the adpod module's hooks. This is called by the corresponding adserver video module. - * PBJS 10: Adding a deprecation warning - */ -function initAdpodHooks() { - logWarn('DEPRECATION NOTICE: Prebid.js is not aware of any transactions requiring the ADPOD video mediatype context. Please open a github issue if you are relying on it as support for it may be removed in a future version.'); - - setupBeforeHookFnOnce(getHook('callPrebidCache'), callPrebidCacheHook); - setupBeforeHookFnOnce(checkAdUnitSetup, checkAdUnitSetupHook); - setupBeforeHookFnOnce(checkVideoBidSetup, checkVideoBidSetupHook); -} - -initAdpodHooks() - -/** - * - * @param {Array[Object]} bids list of 'winning' bids that need to be cached - * @param {Function} callback send the cached bids (or error) back to adserverVideoModule for further processing - }} - */ -export function callPrebidCacheAfterAuction(bids, callback) { - // will call PBC here and execute cb param to initialize player code - store(bids, function (error, cacheIds) { - if (error) { - callback(error, null); - } else { - const successfulCachedBids = []; - for (let i = 0; i < cacheIds.length; i++) { - if (cacheIds[i] !== '') { - successfulCachedBids.push(bids[i]); - } - } - callback(null, successfulCachedBids); - } - }) -} - -/** - * Compare function to be used in sorting long-form bids. This will compare bids on price per second. - */ -export function sortByPricePerSecond(a, b) { - if (a.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket < b.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { - return 1; - } - if (a.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket > b.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { - return -1; - } - return 0; -} - -/** - * This function returns targeting keyvalue pairs for long-form adserver modules. Freewheel and GAM are currently supporting Prebid long-form - * @param {Object} options - Options for targeting. - * @param {Array} options.codes - Array of ad unit codes. - * @param {function} options.callback - Callback function to handle the targeting key-value pairs. - * @returns {Object} Targeting key-value pairs for ad unit codes. - */ -export function getTargeting({ codes, callback } = {}) { - if (!callback) { - logError('No callback function was defined in the getTargeting call. Aborting getTargeting().'); - return; - } - codes = codes || []; - const adPodAdUnits = getAdPodAdUnits(codes); - const bidsReceived = auctionManager.getBidsReceived(); - const competiveExclusionEnabled = config.getConfig('adpod.brandCategoryExclusion'); - const deferCachingSetting = config.getConfig('adpod.deferCaching'); - const deferCachingEnabled = (typeof deferCachingSetting === 'boolean') ? deferCachingSetting : true; - - let bids = getBidsForAdpod(bidsReceived, adPodAdUnits); - bids = (competiveExclusionEnabled || deferCachingEnabled) ? getExclusiveBids(bids) : bids; - - const prioritizeDeals = config.getConfig('adpod.prioritizeDeals'); - if (prioritizeDeals) { - const [otherBids, highPriorityDealBids] = bids.reduce((partitions, bid) => { - const bidDealTier = deepAccess(bid, 'video.dealTier'); - const minDealTier = config.getConfig(`adpod.dealTier.${bid.bidderCode}.minDealTier`); - if (minDealTier && bidDealTier) { - if (bidDealTier >= minDealTier) { - partitions[1].push(bid) - } else { - partitions[0].push(bid) - } - } else if (bidDealTier) { - partitions[1].push(bid) - } else { - partitions[0].push(bid); - } - return partitions; - }, [[], []]); - highPriorityDealBids.sort(sortByPricePerSecond); - otherBids.sort(sortByPricePerSecond); - bids = highPriorityDealBids.concat(otherBids); - } else { - bids.sort(sortByPricePerSecond); - } - - const targeting = {}; - if (deferCachingEnabled === false) { - adPodAdUnits.forEach((adUnit) => { - const adPodTargeting = []; - let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); - - bids - .filter((bid) => bid.adUnitCode === adUnit.code) - .forEach((bid, index, arr) => { - if (bid.video.durationBucket <= adPodDurationSeconds) { - adPodTargeting.push({ - [TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] - }); - adPodDurationSeconds -= bid.video.durationBucket; - } - if (index === arr.length - 1 && adPodTargeting.length > 0) { - adPodTargeting.push({ - [TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] - }); - } - }); - targeting[adUnit.code] = adPodTargeting; - }); - - callback(null, targeting); - } else { - const bidsToCache = []; - adPodAdUnits.forEach((adUnit) => { - let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); - - bids - .filter((bid) => bid.adUnitCode === adUnit.code) - .forEach((bid) => { - if (bid.video.durationBucket <= adPodDurationSeconds) { - bidsToCache.push(bid); - adPodDurationSeconds -= bid.video.durationBucket; - } - }); - }); - - callPrebidCacheAfterAuction(bidsToCache, function (error, bidsSuccessfullyCached) { - if (error) { - callback(error, null); - } else { - const groupedBids = groupBy(bidsSuccessfullyCached, 'adUnitCode'); - Object.keys(groupedBids).forEach((adUnitCode) => { - const adPodTargeting = []; - - groupedBids[adUnitCode].forEach((bid, index, arr) => { - adPodTargeting.push({ - [TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] - }); - - if (index === arr.length - 1 && adPodTargeting.length > 0) { - adPodTargeting.push({ - [TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] - }); - } - }); - targeting[adUnitCode] = adPodTargeting; - }); - - callback(null, targeting); - } - }); - } - return targeting; -} - -/** - * This function returns the adunit of mediaType adpod - * @param {Array} codes adUnitCodes - * @returns {Array[Object]} adunits of mediaType adpod - */ -function getAdPodAdUnits(codes) { - return auctionManager.getAdUnits() - .filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD) - .filter((adUnit) => (codes.length > 0) ? codes.indexOf(adUnit.code) !== -1 : true); -} - -/** - * This function will create compare function to sort on object property - * @param {string} property - * @returns {function} compare function to be used in sorting - */ -function compareOn(property) { - return function compare(a, b) { - if (a[property] < b[property]) { - return 1; - } - if (a[property] > b[property]) { - return -1; - } - return 0; - } -} - -/** - * This function removes bids of same category. It will be used when competitive exclusion is enabled. - * @param {Array[Object]} bidsReceived - * @returns {Array[Object]} unique category bids - */ -function getExclusiveBids(bidsReceived) { - let bids = bidsReceived - .map((bid) => Object.assign({}, bid, { [TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] })); - bids = groupBy(bids, TARGETING_KEY_PB_CAT_DUR); - const filteredBids = []; - Object.keys(bids).forEach((targetingKey) => { - bids[targetingKey].sort(compareOn('responseTimestamp')); - filteredBids.push(bids[targetingKey][0]); - }); - return filteredBids; -} - -/** - * This function returns bids for adpod adunits - * @param {Array[Object]} bidsReceived - * @param {Array[Object]} adPodAdUnits - * @returns {Array[Object]} bids of mediaType adpod - */ -function getBidsForAdpod(bidsReceived, adPodAdUnits) { - const adUnitCodes = adPodAdUnits.map((adUnit) => adUnit.code); - return bidsReceived - .filter((bid) => adUnitCodes.indexOf(bid.adUnitCode) !== -1 && (bid.video && bid.video.context === ADPOD)) -} - -const sharedMethods = { - TARGETING_KEY_PB_CAT_DUR: TARGETING_KEY_PB_CAT_DUR, - TARGETING_KEY_CACHE_ID: TARGETING_KEY_CACHE_ID, - 'getTargeting': getTargeting -} -Object.freeze(sharedMethods); - -module('adpod', function shareAdpodUtilities(...args) { - if (!isPlainObject(args[0])) { - logError('Adpod module needs plain object to share methods with submodule'); - return; - } - function addMethods(object, func) { - for (const name in func) { - object[name] = func[name]; - } - } - addMethods(args[0], sharedMethods); -}); diff --git a/modules/adtelligentBidAdapter.js b/modules/adtelligentBidAdapter.js index 010d2b74409..b7cd1a1dcda 100644 --- a/modules/adtelligentBidAdapter.js +++ b/modules/adtelligentBidAdapter.js @@ -1,6 +1,6 @@ import {_map, deepAccess, flatten, isArray, parseSizesInput} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {ADPOD, BANNER, VIDEO} from '../src/mediaTypes.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {Renderer} from '../src/Renderer.js'; import {chunk} from '../libraries/chunk/chunk.js'; @@ -187,14 +187,6 @@ function prepareBidRequests(bidReq) { bidReqParams.GPID = gpid; } - if (mediaType === VIDEO) { - const context = deepAccess(bidReq, 'mediaTypes.video.context'); - - if (context === ADPOD) { - bidReqParams.Adpod = deepAccess(bidReq, 'mediaTypes.video'); - } - } - return bidReqParams; } @@ -237,18 +229,6 @@ function createBid(bidResponse, bidRequest) { adUrl: bidResponse.adUrl, }); } - if (context === ADPOD) { - Object.assign(bid, { - meta: { - primaryCatId: bidResponse.primaryCatId, - }, - video: { - context: ADPOD, - durationSeconds: bidResponse.durationSeconds - } - }); - } - Object.assign(bid, { vastUrl: bidResponse.vastUrl }); diff --git a/modules/adtrgtmeBidAdapter.js b/modules/adtrgtmeBidAdapter.js index dc15dd2dc9f..5e2319b85df 100644 --- a/modules/adtrgtmeBidAdapter.js +++ b/modules/adtrgtmeBidAdapter.js @@ -11,6 +11,7 @@ import { } from '../src/utils.js'; import { config } from '../src/config.js'; import { hasPurpose1Consent } from '../src/utils/gdpr.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'adtrgtme'; const BIDDER_VERSION = '1.0.7'; @@ -71,7 +72,7 @@ function createORTB(bR, bid) { ...site, }, device: { - dnt: bid?.params?.dnt ? 1 : 0, + dnt: getDNT() ? 1 : 0, ua: bid?.params?.ua || navigator.userAgent, ip, }, diff --git a/modules/adtrueBidAdapter.js b/modules/adtrueBidAdapter.js index 2c4278b9fb8..d503f112d26 100644 --- a/modules/adtrueBidAdapter.js +++ b/modules/adtrueBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { logWarn, isArray, inIframe, isNumber, isStr, deepClone, deepSetValue, logError, deepAccess, isBoolean } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {getStorageManager} from '../src/storageManager.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'adtrue'; const storage = getStorageManager({bidderCode: BIDDER_CODE}); diff --git a/modules/alkimiBidAdapter.js b/modules/alkimiBidAdapter.js index 8e77e2507b7..8d923d26713 100644 --- a/modules/alkimiBidAdapter.js +++ b/modules/alkimiBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {deepAccess, deepClone, generateUUID, replaceAuctionPrice} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import {getStorageManager} from '../src/storageManager.js'; import {VIDEO, BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'alkimi'; const GVLID = 1169; diff --git a/modules/apacdexBidAdapter.js b/modules/apacdexBidAdapter.js index cd433ef2c81..0e669a8fdbc 100644 --- a/modules/apacdexBidAdapter.js +++ b/modules/apacdexBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, isPlainObject, isArray, replaceAuctionPrice, isFn, logError, deepClone } from '../src/utils.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {parseDomain} from '../src/refererDetection.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'apacdex'; const ENDPOINT = 'https://useast.quantumdex.io/auction/pbjs' const USERSYNC = 'https://sync.quantumdex.io/usersync/pbjs' diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 0204c3e02b7..c710789640d 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -21,19 +21,18 @@ import { import {Renderer} from '../src/Renderer.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {getStorageManager} from '../src/storageManager.js'; import {bidderSettings} from '../src/bidderSettings.js'; import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; -import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import { convertKeywordStringToANMap, getANKewyordParamFromMaps, getANKeywordParam } from '../libraries/appnexusUtils/anKeywords.js'; -import {convertCamelToUnderscore, fill, appnexusAliases} from '../libraries/appnexusUtils/anUtils.js'; +import {convertCamelToUnderscore, appnexusAliases} from '../libraries/appnexusUtils/anUtils.js'; import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; import {chunk} from '../libraries/chunk/chunk.js'; @@ -295,10 +294,6 @@ export const spec = { } } - if (config.getConfig('adpod.brandCategoryExclusion')) { - payload.brand_category_uniqueness = true; - } - if (debugObjParams.enabled) { payload.debug = debugObjParams; logInfo('AppNexus Debug Auction Settings:\n\n' + JSON.stringify(debugObjParams, null, 4)); @@ -350,18 +345,6 @@ export const spec = { payload.referrer_detection = refererinfo; } - if (FEATURES.VIDEO) { - const hasAdPodBid = ((bidRequests) || []).find(hasAdPod); - if (hasAdPodBid) { - bidRequests.filter(hasAdPod).forEach(adPodBid => { - const adPodTags = createAdPodRequest(tags, adPodBid); - // don't need the original adpod placement because it's in adPodTags - const nonPodTags = payload.tags.filter(tag => tag.uuid !== adPodBid.bidId); - payload.tags = [...nonPodTags, ...adPodTags]; - }); - } - } - if (bidRequests[0].userIdAsEids?.length > 0) { const eids = []; bidRequests[0].userIdAsEids.forEach(eid => { @@ -612,7 +595,7 @@ function newBid(serverBid, rtbBid, bidderRequest) { } if (FEATURES.VIDEO && rtbBid.rtb.video) { - // shared video properties used for all 3 contexts + // shared video properties used for both stream contexts Object.assign(bid, { width: rtbBid.rtb.video.player_width, height: rtbBid.rtb.video.player_height, @@ -622,17 +605,6 @@ function newBid(serverBid, rtbBid, bidderRequest) { const videoContext = deepAccess(bidRequest, 'mediaTypes.video.context'); switch (videoContext) { - case ADPOD: - const primaryCatId = (APPNEXUS_CATEGORY_MAPPING[rtbBid.brand_category_id]) ? APPNEXUS_CATEGORY_MAPPING[rtbBid.brand_category_id] : null; - bid.meta = Object.assign({}, bid.meta, { primaryCatId }); - const dealTier = rtbBid.deal_priority; - bid.video = { - context: ADPOD, - durationSeconds: Math.floor(rtbBid.rtb.video.duration_ms / 1000), - dealTier - }; - bid.vastUrl = rtbBid.rtb.video.asset_url; - break; case OUTSTREAM: bid.adResponse = serverBid; bid.adResponse.ad = bid.adResponse.ads[0]; @@ -934,11 +906,7 @@ function bidToTag(bid) { const videoMediaType = deepAccess(bid, `mediaTypes.${VIDEO}`); const context = deepAccess(bid, 'mediaTypes.video.context'); - if (videoMediaType && context === 'adpod') { - tag.hb_source = 7; - } else { - tag.hb_source = 1; - } + tag.hb_source = 1; if (bid.mediaType === VIDEO || videoMediaType) { tag.ad_types.push(VIDEO); } @@ -1154,14 +1122,6 @@ function hasDebug(bid) { return !!bid.debug } -function hasAdPod(bid) { - return ( - bid.mediaTypes && - bid.mediaTypes.video && - bid.mediaTypes.video.context === ADPOD - ); -} - function hasOmidSupport(bid) { let hasOmid = false; const bidderParams = bid.params; @@ -1175,54 +1135,6 @@ function hasOmidSupport(bid) { return hasOmid; } -/** - * Expand an adpod placement into a set of request objects according to the - * total adpod duration and the range of duration seconds. Sets minduration/ - * maxduration video property according to requireExactDuration configuration - */ -function createAdPodRequest(tags, adPodBid) { - const { durationRangeSec, requireExactDuration } = adPodBid.mediaTypes.video; - - const numberOfPlacements = getAdPodPlacementNumber(adPodBid.mediaTypes.video); - const maxDuration = Math.max(...durationRangeSec); - - const tagToDuplicate = tags.filter(tag => tag.uuid === adPodBid.bidId); - const request = fill(...tagToDuplicate, numberOfPlacements); - - if (requireExactDuration) { - const divider = Math.ceil(numberOfPlacements / durationRangeSec.length); - const chunked = chunk(request, divider); - - // each configured duration is set as min/maxduration for a subset of requests - durationRangeSec.forEach((duration, index) => { - chunked[index].forEach(tag => { - setVideoProperty(tag, 'minduration', duration); - setVideoProperty(tag, 'maxduration', duration); - }); - }); - } else { - // all maxdurations should be the same - request.forEach(tag => setVideoProperty(tag, 'maxduration', maxDuration)); - } - - return request; -} - -function getAdPodPlacementNumber(videoParams) { - const { adPodDurationSec, durationRangeSec, requireExactDuration } = videoParams; - const minAllowedDuration = Math.min(...durationRangeSec); - const numberOfPlacements = Math.floor(adPodDurationSec / minAllowedDuration); - - return requireExactDuration - ? Math.max(numberOfPlacements, durationRangeSec.length) - : numberOfPlacements; -} - -function setVideoProperty(tag, key, value) { - if (isEmpty(tag.video)) { tag.video = {}; } - tag.video[key] = value; -} - function getRtbBid(tag) { return tag && tag.ads && tag.ads.length && ((tag.ads) || []).find(ad => ad.rtb); } diff --git a/modules/apstreamBidAdapter.js b/modules/apstreamBidAdapter.js index f432c85388f..64c91f60ab0 100644 --- a/modules/apstreamBidAdapter.js +++ b/modules/apstreamBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { generateUUID, deepAccess, createTrackPixelHtml } from '../src/utils.js'; import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRatio.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {getDNT} from '../libraries/dnt/index.js'; const CONSTANTS = { DSU_KEY: 'apr_dsu', diff --git a/modules/asteriobidAnalyticsAdapter.js b/modules/asteriobidAnalyticsAdapter.js index e4f7ee2a767..83c994f5f77 100644 --- a/modules/asteriobidAnalyticsAdapter.js +++ b/modules/asteriobidAnalyticsAdapter.js @@ -229,9 +229,6 @@ function handleEvent(eventType, eventArgs) { case EVENTS.REQUEST_BIDS: { break } - case EVENTS.ADD_AD_UNITS: { - break - } case EVENTS.AD_RENDER_FAILED: { pmEvent.bid = eventArgs.bid pmEvent.message = eventArgs.message diff --git a/modules/axonixBidAdapter.js b/modules/axonixBidAdapter.js index c0b3f334c40..e2177da2f4e 100644 --- a/modules/axonixBidAdapter.js +++ b/modules/axonixBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {deepAccess, isArray, isEmpty, logError, replaceAuctionPrice, triggerPixel} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {ajax} from '../src/ajax.js'; import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'axonix'; const BIDDER_VERSION = '1.0.2'; diff --git a/modules/beachfrontBidAdapter.js b/modules/beachfrontBidAdapter.js index 3f627fe39e0..e6e8074df76 100644 --- a/modules/beachfrontBidAdapter.js +++ b/modules/beachfrontBidAdapter.js @@ -10,8 +10,9 @@ import { import {registerBidder} from '../src/adapters/bidderFactory.js'; import {Renderer} from '../src/Renderer.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import { getFirstSize, getOsVersion, getVideoSizes, getBannerSizes, isConnectedTV, getDoNotTrack, isMobile, isBannerBid, isVideoBid, getBannerBidFloor, getVideoBidFloor, getVideoTargetingParams, getTopWindowLocation } from '../libraries/advangUtils/index.js'; +import { getFirstSize, getOsVersion, getVideoSizes, getBannerSizes, isConnectedTV, isMobile, isBannerBid, isVideoBid, getBannerBidFloor, getVideoBidFloor, getVideoTargetingParams, getTopWindowLocation } from '../libraries/advangUtils/index.js'; import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; const ADAPTER_VERSION = '1.21'; const GVLID = 157; @@ -305,7 +306,7 @@ function createVideoRequestData(bid, bidderRequest) { ua: navigator.userAgent, language: navigator.language, devicetype: isMobile() ? 1 : isConnectedTV() ? 3 : 2, - dnt: getDoNotTrack() ? 1 : 0, + dnt: getDNT() ? 1 : 0, js: 1, geo: {} }, @@ -371,7 +372,7 @@ function createBannerRequestData(bids, bidderRequest) { ua: navigator.userAgent, deviceOs: getOsVersion(), isMobile: isMobile() ? 1 : 0, - dnt: getDoNotTrack() ? 1 : 0, + dnt: getDNT() ? 1 : 0, adapterVersion: ADAPTER_VERSION, adapterName: ADAPTER_NAME }; diff --git a/modules/bmtmBidAdapter.js b/modules/bmtmBidAdapter.js index bc6a4415f97..a5af67e7512 100644 --- a/modules/bmtmBidAdapter.js +++ b/modules/bmtmBidAdapter.js @@ -1,8 +1,8 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { generateUUID, deepAccess, logWarn, deepSetValue, isPlainObject } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'bmtm'; const AD_URL = 'https://one.elitebidder.com/api/hb?sid='; diff --git a/modules/cadent_aperture_mxBidAdapter.js b/modules/cadent_aperture_mxBidAdapter.js index f13bda26102..4a16444553b 100644 --- a/modules/cadent_aperture_mxBidAdapter.js +++ b/modules/cadent_aperture_mxBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { _each, deepAccess, getBidIdParameter, @@ -13,6 +12,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {Renderer} from '../src/Renderer.js'; import {parseDomain} from '../src/refererDetection.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'cadent_aperture_mx'; const ENDPOINT = 'hb.emxdgt.com'; diff --git a/modules/categoryTranslation.js b/modules/categoryTranslation.js deleted file mode 100644 index a0ef902412e..00000000000 --- a/modules/categoryTranslation.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * This module translates iab category to freewheel industry using translation mapping file - * Publisher can set translation file by using setConfig method - * - * Example: - * config.setConfig({ - * 'brandCategoryTranslation': { - * 'translationFile': 'http://sample.com' - * } - * }); - * If publisher has not defined translation file than prebid will use default prebid translation file provided here //cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json - */ - -import {config} from '../src/config.js'; -import {hook, setupBeforeHookFnOnce, ready} from '../src/hook.js'; -import {ajax} from '../src/ajax.js'; -import {logError, timestamp} from '../src/utils.js'; -import {addBidResponse} from '../src/auction.js'; -import {getCoreStorageManager} from '../src/storageManager.js'; -import {timedBidResponseHook} from '../src/utils/perfMetrics.js'; - -export const storage = getCoreStorageManager('categoryTranslation'); -const DEFAULT_TRANSLATION_FILE_URL = 'https://cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json'; -const DEFAULT_IAB_TO_FW_MAPPING_KEY = 'iabToFwMappingkey'; -const DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB = 'iabToFwMappingkeyPub'; -const refreshInDays = 1; - -export const registerAdserver = hook('async', function(adServer) { - let url; - if (adServer === 'freewheel') { - url = DEFAULT_TRANSLATION_FILE_URL; - initTranslation(url, DEFAULT_IAB_TO_FW_MAPPING_KEY); - } -}, 'registerAdserver'); - -ready.then(() => registerAdserver()); - -export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation', function getAdserverCategoryHook(fn, adUnitCode, bid, reject) { - if (!bid) { - return fn.call(this, adUnitCode, bid, reject); // if no bid, call original and let it display warnings - } - - if (!config.getConfig('adpod.brandCategoryExclusion')) { - return fn.call(this, adUnitCode, bid, reject); - } - - const localStorageKey = (config.getConfig('brandCategoryTranslation.translationFile')) ? DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB : DEFAULT_IAB_TO_FW_MAPPING_KEY; - - if (bid.meta && !bid.meta.adServerCatId) { - let mapping = storage.getDataFromLocalStorage(localStorageKey); - if (mapping) { - try { - mapping = JSON.parse(mapping); - } catch (error) { - logError('Failed to parse translation mapping file'); - } - if (bid.meta.primaryCatId && mapping['mapping'] && mapping['mapping'][bid.meta.primaryCatId]) { - bid.meta.adServerCatId = mapping['mapping'][bid.meta.primaryCatId]['id']; - } else { - // This bid will be automatically ignored by adpod module as adServerCatId was not found - bid.meta.adServerCatId = undefined; - } - } else { - logError('Translation mapping data not found in local storage'); - } - } - fn.call(this, adUnitCode, bid, reject); -}); - -export function initTranslation(url, localStorageKey) { - setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50); - let mappingData = storage.getDataFromLocalStorage(localStorageKey); - try { - mappingData = mappingData ? JSON.parse(mappingData) : undefined; - if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { - ajax(url, - { - success: (response) => { - try { - response = JSON.parse(response); - response['lastUpdated'] = timestamp(); - storage.setDataInLocalStorage(localStorageKey, JSON.stringify(response)); - } catch (error) { - logError('Failed to parse translation mapping file'); - } - }, - error: () => { - logError('Failed to load brand category translation file.') - } - }, - ); - } - } catch (error) { - logError('Failed to parse translation mapping file'); - } -} - -function setConfig(config) { - if (config.translationFile) { - // if publisher has defined the translation file, preload that file here - initTranslation(config.translationFile, DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB); - } -} - -config.getConfig('brandCategoryTranslation', config => setConfig(config.brandCategoryTranslation)); diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 14268185027..c1faefb36ec 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -104,10 +104,6 @@ function _buildBid (bid, bidderRequest) { placement.ext = {'pid': bid.params.placementId} - if (bidderRequest.paapi?.enabled) { - placement.ext.ae = bid?.ortb2Imp?.ext?.ae - } - return placement } diff --git a/modules/chtnwBidAdapter.js b/modules/chtnwBidAdapter.js index 3aea0016679..4c904e79596 100644 --- a/modules/chtnwBidAdapter.js +++ b/modules/chtnwBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { generateUUID, _each, @@ -10,6 +9,7 @@ import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { getStorageManager } from '../src/storageManager.js'; import { ajax } from '../src/ajax.js'; import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; +import {getDNT} from '../libraries/dnt/index.js'; const ENDPOINT_URL = 'https://prebid.cht.hinet.net/api/v1'; const BIDDER_CODE = 'chtnw'; const COOKIE_NAME = '__htid'; diff --git a/modules/cointrafficBidAdapter.js b/modules/cointrafficBidAdapter.js index d9394253497..60a3ffdf7da 100644 --- a/modules/cointrafficBidAdapter.js +++ b/modules/cointrafficBidAdapter.js @@ -4,7 +4,7 @@ import { BANNER } from '../src/mediaTypes.js' import { config } from '../src/config.js' import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js'; import { getViewportSize } from '../libraries/viewport/viewport.js' -import { getDNT } from '../libraries/dnt/index.js' +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js index 464499b5f7d..459c27ea756 100644 --- a/modules/connectadBidAdapter.js +++ b/modules/connectadBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, deepSetValue, mergeDeep, logWarn, generateUUID } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js' import {config} from '../src/config.js'; import {tryAppendQueryString} from '../libraries/urlUtils/urlUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'connectad'; const BIDDER_CODE_ALIAS = 'connectadrealtime'; diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 9965cd1cb2b..46b1e5d75a0 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -1,4 +1,4 @@ -import {deepSetValue, isArray, logError, logWarn, parseUrl, triggerPixel, deepAccess, logInfo} from '../src/utils.js'; +import {deepAccess, deepSetValue, logError, logInfo, logWarn, parseUrl, triggerPixel} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; @@ -76,10 +76,6 @@ function imp(buildImp, bidRequest, context) { delete imp.rwdd // oRTB 2.6 field moved to ext - if (!context.fledgeEnabled && imp.ext.igs?.ae) { - delete imp.ext.igs.ae; - } - if (hasVideoMediaType(bidRequest)) { const paramsVideo = bidRequest.params.video; if (paramsVideo !== undefined) { @@ -392,7 +388,7 @@ export const spec = { /** * @param {*} response * @param {ServerRequest} request - * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} + * @return {Bid[] | {bids: Bid[]}} */ interpretResponse: (response, request) => { if (typeof response?.body === 'undefined') { @@ -400,18 +396,7 @@ export const spec = { } const interpretedResponse = CONVERTER.fromORTB({response: response.body, request: request.data}); - const bids = interpretedResponse.bids || []; - - const fledgeAuctionConfigs = response.body?.ext?.igi?.filter(igi => isArray(igi?.igs)) - .flatMap(igi => igi.igs); - if (fledgeAuctionConfigs?.length) { - return { - bids, - paapi: fledgeAuctionConfigs, - }; - } - - return bids; + return interpretedResponse.bids || []; }, /** @@ -503,7 +488,6 @@ function buildContext(bidRequests, bidderRequest) { url: bidderRequest?.refererInfo?.page || '', debug: queryString['pbt_debug'] === '1', noLog: queryString['pbt_nolog'] === '1', - fledgeEnabled: bidderRequest.paapi?.enabled, amp: bidRequests.some(bidRequest => bidRequest.params.integrationMode === 'amp'), networkId: bidRequests.find(bidRequest => bidRequest.params?.networkId)?.params.networkId, publisherId: bidRequests.find(bidRequest => bidRequest.params?.pubid)?.params.pubid, diff --git a/modules/debugging/bidInterceptor.js b/modules/debugging/bidInterceptor.js index 928fba3f10b..4acf543764c 100644 --- a/modules/debugging/bidInterceptor.js +++ b/modules/debugging/bidInterceptor.js @@ -53,7 +53,6 @@ export function makebidInterceptor({utils, BANNER, NATIVE, VIDEO, Renderer}) { match: this.matcher(ruleDef.when, ruleNo), replace: this.replacer(ruleDef.then, ruleNo), options: Object.assign({}, this.DEFAULT_RULE_OPTIONS, ruleDef.options), - paapi: this.paapiReplacer(ruleDef.paapi || [], ruleNo) } }, /** @@ -144,24 +143,6 @@ export function makebidInterceptor({utils, BANNER, NATIVE, VIDEO, Renderer}) { return response; } }, - - paapiReplacer(paapiDef, ruleNo) { - function wrap(configs = []) { - return configs.map(config => { - return Object.keys(config).some(k => !['config', 'igb'].includes(k)) - ? {config} - : config - }); - } - if (Array.isArray(paapiDef)) { - return () => wrap(paapiDef); - } else if (typeof paapiDef === 'function') { - return (...args) => wrap(paapiDef(...args)) - } else { - this.logger.logError(`Invalid 'paapi' definition for debug bid interceptor (in rule #${ruleNo})`); - } - }, - responseDefaults(bid) { const response = { requestId: bid.bidId, @@ -224,12 +205,11 @@ export function makebidInterceptor({utils, BANNER, NATIVE, VIDEO, Renderer}) { * {{}[]} bids? * {*} bidRequest * {function(*)} addBid called once for each mock response - * addPaapiConfig called once for each mock PAAPI config * {function()} done called once after all mock responses have been run through `addBid` * returns {{bids: {}[], bidRequest: {}} remaining bids that did not match any rule (this applies also to * bidRequest.bids) */ - intercept({bids, bidRequest, addBid, addPaapiConfig, done}) { + intercept({bids, bidRequest, addBid, done}) { if (bids == null) { bids = bidRequest.bids; } @@ -238,12 +218,10 @@ export function makebidInterceptor({utils, BANNER, NATIVE, VIDEO, Renderer}) { const callDone = delayExecution(done, matches.length); matches.forEach((match) => { const mockResponse = match.rule.replace(match.bid, bidRequest); - const mockPaapi = match.rule.paapi(match.bid, bidRequest); const delay = match.rule.options.delay; - this.logger.logMessage(`Intercepted bid request (matching rule #${match.rule.no}), mocking response in ${delay}ms. Request, response, PAAPI configs:`, match.bid, mockResponse, mockPaapi) + this.logger.logMessage(`Intercepted bid request (matching rule #${match.rule.no}), mocking response in ${delay}ms. Request, response:`, match.bid, mockResponse) this.setTimeout(() => { mockResponse && addBid(mockResponse, match.bid); - mockPaapi.forEach(cfg => addPaapiConfig(cfg, match.bid, bidRequest)); callDone(); }, delay) }); diff --git a/modules/debugging/debugging.js b/modules/debugging/debugging.js index d5bbc895ae1..1db564ceb95 100644 --- a/modules/debugging/debugging.js +++ b/modules/debugging/debugging.js @@ -108,7 +108,6 @@ export function makeBidderBidInterceptor({utils}) { bids, bidRequest, addBid: wrapCallback(cbs.onBid), - addPaapiConfig: wrapCallback((config, bidRequest) => cbs.onPaapi({bidId: bidRequest.bidId, ...config})), done })); if (bids.length === 0) { diff --git a/modules/debugging/pbsInterceptor.js b/modules/debugging/pbsInterceptor.js index 753f502002d..8e7435337bf 100644 --- a/modules/debugging/pbsInterceptor.js +++ b/modules/debugging/pbsInterceptor.js @@ -4,7 +4,6 @@ export function makePbsInterceptor({createBid, utils}) { onResponse, onError, onBid, - onFledge, }) { let responseArgs; const done = delayExecution(() => onResponse(...responseArgs), bidRequests.length + 1) @@ -22,14 +21,6 @@ export function makePbsInterceptor({createBid, utils}) { .map((req) => interceptBids({ bidRequest: req, addBid, - addPaapiConfig(config, bidRequest, bidderRequest) { - onFledge({ - adUnitCode: bidRequest.adUnitCode, - ortb2: bidderRequest.ortb2, - ortb2Imp: bidRequest.ortb2Imp, - ...config - }) - }, done }).bidRequest) .filter((req) => req.bids.length > 0) diff --git a/modules/deepintentBidAdapter.js b/modules/deepintentBidAdapter.js index c5acc942218..eabcc036cca 100644 --- a/modules/deepintentBidAdapter.js +++ b/modules/deepintentBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { generateUUID, deepSetValue, deepAccess, isArray, isFn, isPlainObject, logError, logWarn } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { COMMON_ORTB_VIDEO_PARAMS, formatResponse } from '../libraries/deepintentUtils/index.js'; import { addDealCustomTargetings, addPMPDeals } from '../libraries/dealUtils/dealUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; const LOG_WARN_PREFIX = 'DeepIntent: '; const BIDDER_CODE = 'deepintent'; diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js deleted file mode 100644 index a7053622102..00000000000 --- a/modules/dfpAdServerVideo.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint prebid/validate-imports: "off" */ -import {registerVideoSupport} from '../src/adServerManager.js'; -import {buildGamVideoUrl, getVastXml, notifyTranslationModule, dep, VAST_TAG_URI_TAGNAME, getBase64BlobContent} from './gamAdServerVideo.js'; - -export const buildDfpVideoUrl = buildGamVideoUrl; -export { getVastXml, notifyTranslationModule, dep, VAST_TAG_URI_TAGNAME, getBase64BlobContent }; - -registerVideoSupport('dfp', { - buildVideoUrl: buildDfpVideoUrl, - getVastXml -}); diff --git a/modules/dfpAdpod.js b/modules/dfpAdpod.js deleted file mode 100644 index 831507dcc5c..00000000000 --- a/modules/dfpAdpod.js +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint prebid/validate-imports: "off" */ -import {registerVideoSupport} from '../src/adServerManager.js'; -import {buildAdpodVideoUrl, adpodUtils} from './gamAdpod.js'; - -export { buildAdpodVideoUrl, adpodUtils }; - -registerVideoSupport('dfp', { - buildAdpodVideoUrl, - getAdpodTargeting: (args) => adpodUtils.getTargeting(args) -}); diff --git a/modules/digitalMatterBidAdapter.js b/modules/digitalMatterBidAdapter.js index 37c01e6a9d9..c0f972d9a3b 100644 --- a/modules/digitalMatterBidAdapter.js +++ b/modules/digitalMatterBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {deepAccess, deepSetValue, getWinDimensions, inIframe, logWarn, parseSizesInput} from '../src/utils.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {hasPurpose1Consent} from '../src/utils/gdpr.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'digitalMatter'; const GVLID = 1345; diff --git a/modules/distroscaleBidAdapter.js b/modules/distroscaleBidAdapter.js index 4737c8bf969..cb7f5636fbd 100644 --- a/modules/distroscaleBidAdapter.js +++ b/modules/distroscaleBidAdapter.js @@ -1,8 +1,8 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { logWarn, isPlainObject, isStr, isArray, isFn, inIframe, mergeDeep, deepSetValue, logError, deepClone } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; import { BANNER } from '../src/mediaTypes.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'distroscale'; const SHORT_CODE = 'ds'; const LOG_WARN_PREFIX = 'DistroScale: '; diff --git a/modules/empowerBidAdapter.js b/modules/empowerBidAdapter.js index 14e8be2a82d..fb8d7d2b620 100644 --- a/modules/empowerBidAdapter.js +++ b/modules/empowerBidAdapter.js @@ -1,262 +1,258 @@ -import { - deepAccess, - mergeDeep, - logError, - replaceMacros, - triggerPixel, - deepSetValue, - isStr, - isArray, - getWinDimensions, -} from "../src/utils.js"; -import { registerBidder } from "../src/adapters/bidderFactory.js"; -import { config } from "../src/config.js"; -import { VIDEO, BANNER } from "../src/mediaTypes.js"; -import { getConnectionType } from "../libraries/connectionInfo/connectionUtils.js"; - -export const ENDPOINT = "https://bid.virgul.com/prebid"; - -const BIDDER_CODE = "empower"; -const GVLID = 1248; - -export const spec = { - code: BIDDER_CODE, - gvlid: GVLID, - supportedMediaTypes: [VIDEO, BANNER], - - isBidRequestValid: (bid) => - !!(bid && bid.params && bid.params.zone && bid.bidder === BIDDER_CODE), - - buildRequests: (bidRequests, bidderRequest) => { - const currencyObj = config.getConfig("currency"); - const currency = (currencyObj && currencyObj.adServerCurrency) || "USD"; - - const request = { - id: bidRequests[0].bidderRequestId, - at: 1, - imp: bidRequests.map((slot) => impression(slot, currency)), - site: { - page: bidderRequest.refererInfo.page, - domain: bidderRequest.refererInfo.domain, - ref: bidderRequest.refererInfo.ref, - publisher: { domain: bidderRequest.refererInfo.domain }, - }, - device: { - ua: navigator.userAgent, - js: 1, - dnt: - navigator.doNotTrack === "yes" || - navigator.doNotTrack === "1" || - navigator.msDoNotTrack === "1" - ? 1 - : 0, - h: screen.height, - w: screen.width, - language: navigator.language, - connectiontype: getConnectionType(), - }, - cur: [currency], - source: { - fd: 1, - tid: bidderRequest.ortb2?.source?.tid, - ext: { - prebid: "$prebid.version$", - }, - }, - user: {}, - regs: {}, - ext: {}, - }; - - if (bidderRequest.gdprConsent) { - request.user = { - ext: { - consent: bidderRequest.gdprConsent.consentString || "", - }, - }; - request.regs = { - ext: { - gdpr: - bidderRequest.gdprConsent.gdprApplies !== undefined - ? bidderRequest.gdprConsent.gdprApplies - : true, - }, - }; - } - - if (bidderRequest.ortb2?.source?.ext?.schain) { - request.schain = bidderRequest.ortb2.source.ext.schain; - } - - let bidUserIdAsEids = deepAccess(bidRequests, "0.userIdAsEids"); - if (isArray(bidUserIdAsEids) && bidUserIdAsEids.length > 0) { - deepSetValue(request, "user.eids", bidUserIdAsEids); - } - - const commonFpd = bidderRequest.ortb2 || {}; - const { user, device, site, bcat, badv } = commonFpd; - if (site) { - mergeDeep(request, { site: site }); - } - if (user) { - mergeDeep(request, { user: user }); - } - if (badv) { - mergeDeep(request, { badv: badv }); - } - if (bcat) { - mergeDeep(request, { bcat: bcat }); - } - - if (user?.geo && device?.geo) { - request.device.geo = { ...request.device.geo, ...device.geo }; - request.user.geo = { ...request.user.geo, ...user.geo }; - } else { - if (user?.geo || device?.geo) { - request.user.geo = request.device.geo = user?.geo - ? { ...request.user.geo, ...user.geo } - : { ...request.user.geo, ...device.geo }; - } - } - - if (bidderRequest.ortb2?.device) { - mergeDeep(request.device, bidderRequest.ortb2.device); - } - - return { - method: "POST", - url: ENDPOINT, - data: JSON.stringify(request), - }; - }, - - interpretResponse: (bidResponse, bidRequest) => { - const idToImpMap = {}; - const idToBidMap = {}; - - if (!bidResponse["body"]) { - return []; - } - if (!bidRequest.data) { - return []; - } - const requestImps = parse(bidRequest.data); - if (!requestImps) { - return []; - } - requestImps.imp.forEach((imp) => { - idToImpMap[imp.id] = imp; - }); - bidResponse = bidResponse.body; - if (bidResponse) { - bidResponse.seatbid.forEach((seatBid) => - seatBid.bid.forEach((bid) => { - idToBidMap[bid.impid] = bid; - }) - ); - } - const bids = []; - Object.keys(idToImpMap).forEach((id) => { - const imp = idToImpMap[id]; - const result = idToBidMap[id]; - - if (result) { - const bid = { - requestId: id, - cpm: result.price, - creativeId: result.crid, - ttl: 300, - netRevenue: true, - mediaType: imp.video ? VIDEO : BANNER, - currency: bidResponse.cur, - }; - if (imp.video) { - bid.vastXml = result.adm; - } else if (imp.banner) { - bid.ad = result.adm; - } - bid.width = result.w; - bid.height = result.h; - if (result.burl) bid.burl = result.burl; - if (result.nurl) bid.nurl = result.nurl; - if (result.adomain) { - bid.meta = { - advertiserDomains: result.adomain, - }; - } - bids.push(bid); - } - }); - return bids; - }, - - onBidWon: (bid) => { - if (bid.nurl && isStr(bid.nurl)) { - bid.nurl = replaceMacros(bid.nurl, { - AUCTION_PRICE: bid.cpm, - AUCTION_CURRENCY: bid.cur, - }); - triggerPixel(bid.nurl); - } - }, -}; - -function impression(slot, currency) { - let bidFloorFromModule; - if (typeof slot.getFloor === "function") { - const floorInfo = slot.getFloor({ - currency: "USD", - mediaType: "*", - size: "*", - }); - bidFloorFromModule = - floorInfo?.currency === "USD" ? floorInfo?.floor : undefined; - } - const imp = { - id: slot.bidId, - bidfloor: bidFloorFromModule || slot.params.bidfloor || 0, - bidfloorcur: - (bidFloorFromModule && "USD") || - slot.params.bidfloorcur || - currency || - "USD", - tagid: "" + (slot.params.zone || ""), - }; - - if (slot.mediaTypes.banner) { - imp.banner = bannerImpression(slot); - } else if (slot.mediaTypes.video) { - imp.video = deepAccess(slot, "mediaTypes.video"); - } - imp.ext = slot.params || {}; - const { innerWidth, innerHeight } = getWinDimensions(); - imp.ext.ww = innerWidth || ""; - imp.ext.wh = innerHeight || ""; - return imp; -} - -function bannerImpression(slot) { - const sizes = slot.mediaTypes.banner.sizes || slot.sizes; - return { - format: sizes.map((s) => ({ w: s[0], h: s[1] })), - w: sizes[0][0], - h: sizes[0][1], - }; -} - -function parse(rawResponse) { - try { - if (rawResponse) { - if (typeof rawResponse === "object") { - return rawResponse; - } else { - return JSON.parse(rawResponse); - } - } - } catch (ex) { - logError("empowerBidAdapter", "ERROR", ex); - } - return null; -} - -registerBidder(spec); +import { + deepAccess, + mergeDeep, + logError, + replaceMacros, + triggerPixel, + deepSetValue, + isStr, + isArray, + getWinDimensions, +} from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { config } from "../src/config.js"; +import { VIDEO, BANNER } from "../src/mediaTypes.js"; +import { getConnectionType } from "../libraries/connectionInfo/connectionUtils.js"; +import {getDNT} from "../libraries/dnt/index.js"; + +export const ENDPOINT = "https://bid.virgul.com/prebid"; + +const BIDDER_CODE = "empower"; +const GVLID = 1248; + +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [VIDEO, BANNER], + + isBidRequestValid: (bid) => + !!(bid && bid.params && bid.params.zone && bid.bidder === BIDDER_CODE), + + buildRequests: (bidRequests, bidderRequest) => { + const currencyObj = config.getConfig("currency"); + const currency = (currencyObj && currencyObj.adServerCurrency) || "USD"; + + const request = { + id: bidRequests[0].bidderRequestId, + at: 1, + imp: bidRequests.map((slot) => impression(slot, currency)), + site: { + page: bidderRequest.refererInfo.page, + domain: bidderRequest.refererInfo.domain, + ref: bidderRequest.refererInfo.ref, + publisher: { domain: bidderRequest.refererInfo.domain }, + }, + device: { + ua: navigator.userAgent, + js: 1, + dnt: getDNT() ? 1 : 0, + h: screen.height, + w: screen.width, + language: navigator.language, + connectiontype: getConnectionType(), + }, + cur: [currency], + source: { + fd: 1, + tid: bidderRequest.ortb2?.source?.tid, + ext: { + prebid: "$prebid.version$", + }, + }, + user: {}, + regs: {}, + ext: {}, + }; + + if (bidderRequest.gdprConsent) { + request.user = { + ext: { + consent: bidderRequest.gdprConsent.consentString || "", + }, + }; + request.regs = { + ext: { + gdpr: + bidderRequest.gdprConsent.gdprApplies !== undefined + ? bidderRequest.gdprConsent.gdprApplies + : true, + }, + }; + } + + if (bidderRequest.ortb2?.source?.ext?.schain) { + request.schain = bidderRequest.ortb2.source.ext.schain; + } + + let bidUserIdAsEids = deepAccess(bidRequests, "0.userIdAsEids"); + if (isArray(bidUserIdAsEids) && bidUserIdAsEids.length > 0) { + deepSetValue(request, "user.eids", bidUserIdAsEids); + } + + const commonFpd = bidderRequest.ortb2 || {}; + const { user, device, site, bcat, badv } = commonFpd; + if (site) { + mergeDeep(request, { site: site }); + } + if (user) { + mergeDeep(request, { user: user }); + } + if (badv) { + mergeDeep(request, { badv: badv }); + } + if (bcat) { + mergeDeep(request, { bcat: bcat }); + } + + if (user?.geo && device?.geo) { + request.device.geo = { ...request.device.geo, ...device.geo }; + request.user.geo = { ...request.user.geo, ...user.geo }; + } else { + if (user?.geo || device?.geo) { + request.user.geo = request.device.geo = user?.geo + ? { ...request.user.geo, ...user.geo } + : { ...request.user.geo, ...device.geo }; + } + } + + if (bidderRequest.ortb2?.device) { + mergeDeep(request.device, bidderRequest.ortb2.device); + } + + return { + method: "POST", + url: ENDPOINT, + data: JSON.stringify(request), + }; + }, + + interpretResponse: (bidResponse, bidRequest) => { + const idToImpMap = {}; + const idToBidMap = {}; + + if (!bidResponse["body"]) { + return []; + } + if (!bidRequest.data) { + return []; + } + const requestImps = parse(bidRequest.data); + if (!requestImps) { + return []; + } + requestImps.imp.forEach((imp) => { + idToImpMap[imp.id] = imp; + }); + bidResponse = bidResponse.body; + if (bidResponse) { + bidResponse.seatbid.forEach((seatBid) => + seatBid.bid.forEach((bid) => { + idToBidMap[bid.impid] = bid; + }) + ); + } + const bids = []; + Object.keys(idToImpMap).forEach((id) => { + const imp = idToImpMap[id]; + const result = idToBidMap[id]; + + if (result) { + const bid = { + requestId: id, + cpm: result.price, + creativeId: result.crid, + ttl: 300, + netRevenue: true, + mediaType: imp.video ? VIDEO : BANNER, + currency: bidResponse.cur, + }; + if (imp.video) { + bid.vastXml = result.adm; + } else if (imp.banner) { + bid.ad = result.adm; + } + bid.width = result.w; + bid.height = result.h; + if (result.burl) bid.burl = result.burl; + if (result.nurl) bid.nurl = result.nurl; + if (result.adomain) { + bid.meta = { + advertiserDomains: result.adomain, + }; + } + bids.push(bid); + } + }); + return bids; + }, + + onBidWon: (bid) => { + if (bid.nurl && isStr(bid.nurl)) { + bid.nurl = replaceMacros(bid.nurl, { + AUCTION_PRICE: bid.cpm, + AUCTION_CURRENCY: bid.cur, + }); + triggerPixel(bid.nurl); + } + }, +}; + +function impression(slot, currency) { + let bidFloorFromModule; + if (typeof slot.getFloor === "function") { + const floorInfo = slot.getFloor({ + currency: "USD", + mediaType: "*", + size: "*", + }); + bidFloorFromModule = + floorInfo?.currency === "USD" ? floorInfo?.floor : undefined; + } + const imp = { + id: slot.bidId, + bidfloor: bidFloorFromModule || slot.params.bidfloor || 0, + bidfloorcur: + (bidFloorFromModule && "USD") || + slot.params.bidfloorcur || + currency || + "USD", + tagid: "" + (slot.params.zone || ""), + }; + + if (slot.mediaTypes.banner) { + imp.banner = bannerImpression(slot); + } else if (slot.mediaTypes.video) { + imp.video = deepAccess(slot, "mediaTypes.video"); + } + imp.ext = slot.params || {}; + const { innerWidth, innerHeight } = getWinDimensions(); + imp.ext.ww = innerWidth || ""; + imp.ext.wh = innerHeight || ""; + return imp; +} + +function bannerImpression(slot) { + const sizes = slot.mediaTypes.banner.sizes || slot.sizes; + return { + format: sizes.map((s) => ({ w: s[0], h: s[1] })), + w: sizes[0][0], + h: sizes[0][1], + }; +} + +function parse(rawResponse) { + try { + if (rawResponse) { + if (typeof rawResponse === "object") { + return rawResponse; + } else { + return JSON.parse(rawResponse); + } + } + } catch (ex) { + logError("empowerBidAdapter", "ERROR", ex); + } + return null; +} + +registerBidder(spec); diff --git a/modules/express.js b/modules/express.js deleted file mode 100644 index a2998baed07..00000000000 --- a/modules/express.js +++ /dev/null @@ -1,210 +0,0 @@ -import { logMessage, logWarn, logError, logInfo } from '../src/utils.js'; -import {getGlobal} from '../src/prebidGlobal.js'; - -const MODULE_NAME = 'express'; -const pbjsInstance = getGlobal(); - -/** - * Express Module - * - * The express module allows the initiation of Prebid.js auctions automatically based on calls such as gpt.defineSlot. - * It works by monkey-patching the gpt methods and overloading their functionality. In order for this module to be - * used gpt must be included in the page, this module must be included in the Prebid.js bundle, and a call to - * pbjs.express() must be made. - * - * @param {Object[]} [adUnits = pbjs.adUnits] - an array of adUnits for express to operate on. - */ -pbjsInstance.express = function(adUnits = pbjsInstance.adUnits) { - logMessage('loading ' + MODULE_NAME); - - if (adUnits.length === 0) { - logWarn('no valid adUnits found, not loading ' + MODULE_NAME); - } - - // store gpt slots in a more performant hash lookup by elementId (adUnit code) - var gptSlotCache = {}; - // put adUnits in a more performant hash lookup by code. - var adUnitsCache = adUnits.reduce(function (cache, adUnit) { - if (adUnit.code && adUnit.bids) { - cache[adUnit.code] = adUnit; - } else { - logError('misconfigured adUnit', null, adUnit); - } - return cache; - }, {}); - - window.googletag = window.googletag || {}; - window.googletag.cmd = window.googletag.cmd || []; - window.googletag.cmd.push(function () { - // verify all necessary gpt functions exist - var gpt = window.googletag; - var pads = gpt.pubads; - if (!gpt.display || !gpt.enableServices || typeof pads !== 'function' || !pads().refresh || !pads().disableInitialLoad || !pads().getSlots || !pads().enableSingleRequest) { - logError('could not bind to gpt googletag api'); - return; - } - logMessage('running'); - - // function to convert google tag slot sizes to [[w,h],...] - function mapGptSlotSizes(aGPTSlotSizes) { - var aSlotSizes = []; - for (var i = 0; i < aGPTSlotSizes.length; i++) { - try { - aSlotSizes.push([aGPTSlotSizes[i].getWidth(), aGPTSlotSizes[i].getHeight()]); - } catch (e) { - logWarn('slot size ' + aGPTSlotSizes[i].toString() + ' not supported by' + MODULE_NAME); - } - } - return aSlotSizes; - } - - // a helper function to verify slots or get slots if not present - function defaultSlots(slots) { - return Array.isArray(slots) - ? slots.slice() - // eslint-disable-next-line no-undef - : googletag.pubads().getSlots().slice(); - } - - // maps gpt slots to adUnits, matches are copied to new array and removed from passed array. - function pickAdUnits(gptSlots) { - var adUnits = []; - // traverse backwards (since gptSlots is mutated) to find adUnits in cache and remove non-mapped slots - for (var i = gptSlots.length - 1; i > -1; i--) { - const gptSlot = gptSlots[i]; - const elemId = gptSlot.getSlotElementId(); - const adUnit = adUnitsCache[elemId]; - - if (adUnit) { - gptSlotCache[elemId] = gptSlot; // store by elementId - adUnit.sizes = adUnit.sizes || mapGptSlotSizes(gptSlot.getSizes()); - adUnits.push(adUnit); - gptSlots.splice(i, 1); - } - } - - return adUnits; - } - - // store original gpt functions that will be overridden - var fGptDisplay = gpt.display; - var fGptEnableServices = gpt.enableServices; - var fGptRefresh = pads().refresh; - var fGptDisableInitialLoad = pads().disableInitialLoad; - var fGptEnableSingleRequest = pads().enableSingleRequest; - - // override googletag.enableServices() - // - make sure fGptDisableInitialLoad() has been called so we can - // better control when slots are displayed, then call original - // fGptEnableServices() - gpt.enableServices = function () { - if (!bInitialLoadDisabled) { - fGptDisableInitialLoad.apply(pads()); - } - return fGptEnableServices.apply(gpt, arguments); - }; - - // override googletag.display() - // - call the real fGptDisplay(). this won't initiate auctions because we've disabled initial load - // - define all corresponding rubicon slots - // - if disableInitialLoad() has been called by the pub, done - // - else run an auction and call the real fGptRefresh() to - // initiate the DFP request - gpt.display = function (sElementId) { - logInfo('display:', sElementId); - // call original gpt display() function - fGptDisplay.apply(gpt, arguments); - - // if not SRA mode, get only the gpt slot corresponding to sEementId - var aGptSlots; - if (!bEnabledSRA) { - // eslint-disable-next-line no-undef - aGptSlots = googletag.pubads().getSlots().filter(function (oGptSlot) { - return oGptSlot.getSlotElementId() === sElementId; - }); - } - - aGptSlots = defaultSlots(aGptSlots).filter(function (gptSlot) { - return !gptSlot._displayed; - }); - - aGptSlots.forEach(function (gptSlot) { - gptSlot._displayed = true; - }); - - var adUnits = pickAdUnits(/* mutated: */ aGptSlots); - - if (!bInitialLoadDisabled) { - if (aGptSlots.length) { - fGptRefresh.apply(pads(), [aGptSlots]); - } - - if (adUnits.length) { - pbjsInstance.requestBids({ - adUnits: adUnits, - bidsBackHandler: function () { - pbjsInstance.setTargetingForGPTAsync(); - fGptRefresh.apply(pads(), [ - adUnits.map(function (adUnit) { - return gptSlotCache[adUnit.code]; - }) - ]); - } - }); - } - } - }; - - // override gpt refresh() function - // - run auctions for provided gpt slots, then initiate ad-server call - pads().refresh = function (aGptSlots, options) { - logInfo('refresh:', aGptSlots); - // get already displayed adUnits from aGptSlots if provided, else all defined gptSlots - aGptSlots = defaultSlots(aGptSlots); - var adUnits = pickAdUnits(/* mutated: */ aGptSlots).filter(function (adUnit) { - return gptSlotCache[adUnit.code]._displayed; - }); - - if (aGptSlots.length) { - fGptRefresh.apply(pads(), [aGptSlots, options]); - } - - if (adUnits.length) { - pbjsInstance.requestBids({ - adUnits: adUnits, - bidsBackHandler: function () { - pbjsInstance.setTargetingForGPTAsync(); - fGptRefresh.apply(pads(), [ - adUnits.map(function (adUnit) { - return gptSlotCache[adUnit.code]; - }), - options - ]); - } - }); - } - }; - - // override gpt disableInitialLoad function - // Register that initial load was called, meaning calls to display() - // should not initiate an ad-server request. Instead a call to - // refresh() will be needed to iniate the request. - // We will assume the pub is using this the correct way, calling it - // before enableServices() - var bInitialLoadDisabled = false; - pads().disableInitialLoad = function () { - bInitialLoadDisabled = true; - return fGptDisableInitialLoad.apply(window.googletag.pubads(), arguments); - }; - - // override gpt useSingleRequest function - // Register that SRA has been turned on - // We will assume the pub is using this the correct way, calling it - // before enableServices() - var bEnabledSRA = false; - pads().enableSingleRequest = function () { - bEnabledSRA = true; - return fGptEnableSingleRequest.apply(window.googletag.pubads(), arguments); - }; - }); -}; diff --git a/modules/freeWheelAdserverVideo.js b/modules/freeWheelAdserverVideo.js deleted file mode 100644 index cb4bd938373..00000000000 --- a/modules/freeWheelAdserverVideo.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * This module adds Freewheel support for Video to Prebid. - */ - -import { registerVideoSupport } from '../src/adServerManager.js'; -import { getHook, submodule } from '../src/hook.js'; - -export const adpodUtils = {}; -export function notifyTranslationModule(fn) { - fn.call(this, 'freewheel'); -} - -getHook('registerAdserver').before(notifyTranslationModule); - -registerVideoSupport('freewheel', { - getTargeting: (args) => adpodUtils.getTargeting(args) -}); - -submodule('adpod', adpodUtils); diff --git a/modules/gamAdServerVideo.js b/modules/gamAdServerVideo.js index b97f4ff598c..abf1a5d6b25 100644 --- a/modules/gamAdServerVideo.js +++ b/modules/gamAdServerVideo.js @@ -9,7 +9,6 @@ import { auctionManager } from '../src/auctionManager.js'; import { config } from '../src/config.js'; import { EVENTS } from '../src/constants.js'; import * as events from '../src/events.js'; -import { getHook } from '../src/hook.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { targeting } from '../src/targeting.js'; import { @@ -183,12 +182,6 @@ export function buildGamVideoUrl(options) { return buildUrl(Object.assign({}, GAM_ENDPOINT, urlComponents, { search: queryParams })); } -export function notifyTranslationModule(fn) { - fn.call(this, 'dfp'); -} - -if (config.getConfig('brandCategoryTranslation.translationFile')) { getHook('registerAdserver').before(notifyTranslationModule); } - /** * Builds a video url from a base dfp video url and a winning bid, appending * Prebid-specific key-values. diff --git a/modules/gamAdpod.js b/modules/gamAdpod.js deleted file mode 100644 index c21c71c0c3c..00000000000 --- a/modules/gamAdpod.js +++ /dev/null @@ -1,95 +0,0 @@ -import {submodule} from '../src/hook.js'; -import {buildUrl, deepAccess, formatQS, logError, parseSizesInput} from '../src/utils.js'; -import {auctionManager} from '../src/auctionManager.js'; -import {DEFAULT_GAM_PARAMS, GAM_ENDPOINT, gdprParams} from '../libraries/gamUtils/gamUtils.js'; -import {registerVideoSupport} from '../src/adServerManager.js'; - -export const adpodUtils = {}; - -/** - * @typedef {Object} DfpAdpodOptions - * - * @param {string} code Ad Unit code - * @param {Object} params Query params which should be set on the DFP request. - * These will override this module's defaults whenever they conflict. - * @param {function} callback Callback function to execute when master tag is ready - */ - -/** - * Creates master tag url for long-form - * @param {DfpAdpodOptions} options - * @returns {string} A URL which calls DFP with custom adpod targeting key values to compete with rest of the demand in DFP - */ -export function buildAdpodVideoUrl({code, params, callback} = {}) { - // TODO: the public API for this does not take in enough info to fill all DFP params (adUnit/bid), - // and is marked "alpha": https://docs.prebid.org/dev-docs/publisher-api-reference/adServers.gam.buildAdpodVideoUrl.html - if (!params || !callback) { - logError(`A params object and a callback is required to use pbjs.adServers.gam.buildAdpodVideoUrl`); - return; - } - - const derivedParams = { - correlator: Date.now(), - sz: getSizeForAdUnit(code), - url: encodeURIComponent(location.href), - }; - - function getSizeForAdUnit(code) { - const adUnit = auctionManager.getAdUnits() - .filter((adUnit) => adUnit.code === code) - const sizes = deepAccess(adUnit[0], 'mediaTypes.video.playerSize'); - return parseSizesInput(sizes).join('|'); - } - - adpodUtils.getTargeting({ - 'codes': [code], - 'callback': createMasterTag - }); - - function createMasterTag(err, targeting) { - if (err) { - callback(err, null); - return; - } - - const initialValue = { - [adpodUtils.TARGETING_KEY_PB_CAT_DUR]: undefined, - [adpodUtils.TARGETING_KEY_CACHE_ID]: undefined - }; - let customParams = {}; - if (targeting[code]) { - customParams = targeting[code].reduce((acc, curValue) => { - if (Object.keys(curValue)[0] === adpodUtils.TARGETING_KEY_PB_CAT_DUR) { - acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] = (typeof acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] !== 'undefined') ? acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] + ',' + curValue[adpodUtils.TARGETING_KEY_PB_CAT_DUR] : curValue[adpodUtils.TARGETING_KEY_PB_CAT_DUR]; - } else if (Object.keys(curValue)[0] === adpodUtils.TARGETING_KEY_CACHE_ID) { - acc[adpodUtils.TARGETING_KEY_CACHE_ID] = curValue[adpodUtils.TARGETING_KEY_CACHE_ID] - } - return acc; - }, initialValue); - } - - const encodedCustomParams = encodeURIComponent(formatQS(customParams)); - - const queryParams = Object.assign({}, - DEFAULT_GAM_PARAMS, - derivedParams, - params, - { cust_params: encodedCustomParams }, - gdprParams(), - ); - - const masterTag = buildUrl({ - ...GAM_ENDPOINT, - search: queryParams - }); - - callback(null, masterTag); - } -} - -registerVideoSupport('gam', { - buildAdpodVideoUrl: buildAdpodVideoUrl, - getAdpodTargeting: (args) => adpodUtils.getTargeting(args) -}); - -submodule('adpod', adpodUtils); diff --git a/modules/gmosspBidAdapter.js b/modules/gmosspBidAdapter.js index 7bff19bb2c0..28b2d7cb7b8 100644 --- a/modules/gmosspBidAdapter.js +++ b/modules/gmosspBidAdapter.js @@ -1,6 +1,5 @@ import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js'; import { tryAppendQueryString } from '../libraries/urlUtils/urlUtils.js'; -import {getDNT} from '../libraries/dnt/index.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { @@ -51,7 +50,6 @@ export const spec = { const urlInfo = getUrlInfo(bidderRequest.refererInfo); const cur = getCurrencyType(bidderRequest); - const dnt = getDNT() ? '1' : '0'; for (let i = 0; i < validBidRequests.length; i++) { let queryString = ''; @@ -76,7 +74,6 @@ export const spec = { queryString = tryAppendQueryString(queryString, 'meta_url', urlInfo.canonicalLink); queryString = tryAppendQueryString(queryString, 'ref', urlInfo.ref); queryString = tryAppendQueryString(queryString, 'cur', cur); - queryString = tryAppendQueryString(queryString, 'dnt', dnt); bidRequests.push({ method: 'GET', diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js index 5c936767cdf..3677408db0e 100644 --- a/modules/growthCodeAnalyticsAdapter.js +++ b/modules/growthCodeAnalyticsAdapter.js @@ -93,11 +93,6 @@ const growthCodeAnalyticsAdapter = Object.assign(adapter({url: url, analyticsTyp break; } - case EVENTS.ADD_AD_UNITS: { - data = eventData; - break; - } - case EVENTS.NO_BID: { data = eventData break; diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index 3f7339a4f08..cb251230899 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -7,6 +7,7 @@ import {getStorageManager} from '../src/storageManager.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -280,7 +281,7 @@ function _getDeviceData(ortb2Data) { ipv6: _device.ipv6, ua: _device.ua, sua: _device.sua ? JSON.stringify(_device.sua) : undefined, - dnt: _device.dnt, + dnt: getDNT() ? 1 : 0, os: _device.os, osv: _device.osv, dt: _device.devicetype, @@ -376,7 +377,6 @@ function buildRequests(validBidRequests, bidderRequest) { const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest); const eids = getEids(userId); const gpid = deepAccess(ortb2Imp, 'ext.gpid'); - const paapiEligible = deepAccess(ortb2Imp, 'ext.ae') === 1 let sizes = [1, 1]; let data = {}; data.displaymanager = 'Prebid.js - gumgum'; @@ -465,9 +465,6 @@ function buildRequests(validBidRequests, bidderRequest) { } else { // legacy params data = { ...data, ...handleLegacyParams(params, sizes) }; } - if (paapiEligible) { - data.ae = paapiEligible - } if (gdprConsent) { data.gdprApplies = gdprConsent.gdprApplies ? 1 : 0; } diff --git a/modules/hadronAnalyticsAdapter.js b/modules/hadronAnalyticsAdapter.js index c01e33bc6a2..db6909b2036 100644 --- a/modules/hadronAnalyticsAdapter.js +++ b/modules/hadronAnalyticsAdapter.js @@ -111,11 +111,6 @@ const hadronAnalyticsAdapter = Object.assign(adapter({url: HADRON_ANALYTICS_URL, break; } - case EVENTS.ADD_AD_UNITS: { - data = args; - break; - } - case EVENTS.AD_RENDER_FAILED: { data = args; break; diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js index 49ffe99245d..3cc74429b50 100644 --- a/modules/impactifyBidAdapter.js +++ b/modules/impactifyBidAdapter.js @@ -1,11 +1,11 @@ 'use strict'; -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, deepSetValue, generateUUID, getWinDimensions, isPlainObject } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; import { ajax } from '../src/ajax.js'; import { getStorageManager } from '../src/storageManager.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/invisiblyAnalyticsAdapter.js b/modules/invisiblyAnalyticsAdapter.js index d6b5fc3efef..e835df6ce47 100644 --- a/modules/invisiblyAnalyticsAdapter.js +++ b/modules/invisiblyAnalyticsAdapter.js @@ -27,7 +27,6 @@ const { BIDDER_DONE, SET_TARGETING, REQUEST_BIDS, - ADD_AD_UNITS, AD_RENDER_FAILED, } = EVENTS; @@ -187,10 +186,6 @@ function handleEvent(eventType, eventArgs) { invisiblyEvent = eventArgs; break; } - case ADD_AD_UNITS: { - invisiblyEvent = eventArgs; - break; - } case AD_RENDER_FAILED: { invisiblyEvent = eventArgs; break; diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 1df9570aab8..da01c3daa07 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -686,8 +686,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r = addRequestedFeatureToggles(r, FEATURE_TOGGLES.REQUESTED_FEATURE_TOGGLES) // getting ixdiags for adunits of the video, outstream & multi format (MF) style - const fledgeEnabled = deepAccess(bidderRequest, 'paapi.enabled') - const ixdiag = buildIXDiag(validBidRequests, fledgeEnabled); + const ixdiag = buildIXDiag(validBidRequests); for (const key in ixdiag) { r.ext.ixdiag[key] = ixdiag[key]; } @@ -954,8 +953,6 @@ function addImpressions(impressions, impKeys, r, adUnitIndex) { const dfpAdUnitCode = impressions[impKeys[adUnitIndex]].dfp_ad_unit_code; const tid = impressions[impKeys[adUnitIndex]].tid; const sid = impressions[impKeys[adUnitIndex]].sid; - const auctionEnvironment = impressions[impKeys[adUnitIndex]].ae; - const paapi = impressions[impKeys[adUnitIndex]].paapi; const bannerImpressions = impressionObjects.filter(impression => BANNER in impression); const otherImpressions = impressionObjects.filter(impression => !(BANNER in impression)); @@ -1005,7 +1002,7 @@ function addImpressions(impressions, impKeys, r, adUnitIndex) { _bannerImpression.banner.pos = position; } - if (dfpAdUnitCode || gpid || tid || sid || auctionEnvironment || externalID || paapi) { + if (dfpAdUnitCode || gpid || tid || sid || externalID) { _bannerImpression.ext = {}; _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; @@ -1013,12 +1010,6 @@ function addImpressions(impressions, impKeys, r, adUnitIndex) { _bannerImpression.ext.tid = tid; _bannerImpression.ext.sid = sid; _bannerImpression.ext.externalID = externalID; - - // enable fledge auction - if (Number(auctionEnvironment) === 1) { - _bannerImpression.ext.ae = 1; - _bannerImpression.ext.paapi = paapi; - } } if ('bidfloor' in bannerImps[0]) { @@ -1272,10 +1263,9 @@ function addIdentifiersInfo(impressions, r, impKeys, adUnitIndex, payload, baseU * Calculates IX diagnostics values and packages them into an object * * @param {Array} validBidRequests - The valid bid requests from prebid - * @param {boolean} fledgeEnabled - Flag indicating if protected audience (fledge) is enabled * @return {Object} IX diag values for ad units */ -function buildIXDiag(validBidRequests, fledgeEnabled) { +function buildIXDiag(validBidRequests) { var adUnitMap = validBidRequests .map(bidRequest => bidRequest.adUnitCode) .filter((value, index, arr) => arr.indexOf(value) === index); @@ -1292,7 +1282,6 @@ function buildIXDiag(validBidRequests, fledgeEnabled) { version: '$prebid.version$', url: window.location.href.split('?')[0], vpd: defaultVideoPlacement, - ae: fledgeEnabled, eidLength: allEids.length }; @@ -1417,23 +1406,6 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps, bidde bannerImps[validBidRequest.adUnitCode].tagId = deepAccess(validBidRequest, 'params.tagId'); bannerImps[validBidRequest.adUnitCode].pos = deepAccess(validBidRequest, 'mediaTypes.banner.pos'); - // Add Fledge flag if enabled - const fledgeEnabled = deepAccess(bidderRequest, 'paapi.enabled') - if (fledgeEnabled) { - const auctionEnvironment = deepAccess(validBidRequest, 'ortb2Imp.ext.ae') - const paapi = deepAccess(validBidRequest, 'ortb2Imp.ext.paapi') - if (paapi) { - bannerImps[validBidRequest.adUnitCode].paapi = paapi - } - if (auctionEnvironment) { - if (isInteger(auctionEnvironment)) { - bannerImps[validBidRequest.adUnitCode].ae = auctionEnvironment; - } else { - logWarn('error setting auction environment flag - must be an integer') - } - } - } - // AdUnit-Specific First Party Data const adUnitFPD = deepAccess(validBidRequest, 'ortb2Imp.ext.data'); if (adUnitFPD) { @@ -1766,9 +1738,6 @@ export const spec = { const bids = []; let bid = null; - // Extract the FLEDGE auction configuration list from the response - let fledgeAuctionConfigs = deepAccess(serverResponse, 'body.ext.protectedAudienceAuctionConfigs') || []; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); if (!serverResponse.hasOwnProperty('body')) { @@ -1812,29 +1781,7 @@ export const spec = { } } } - - if (Array.isArray(fledgeAuctionConfigs) && fledgeAuctionConfigs.length > 0) { - // Validate and filter fledgeAuctionConfigs - fledgeAuctionConfigs = fledgeAuctionConfigs.filter(config => { - if (!isValidAuctionConfig(config)) { - logWarn('Malformed auction config detected:', config); - return false; - } - return true; - }); - - try { - return { - bids, - paapi: fledgeAuctionConfigs, - }; - } catch (error) { - logWarn('Error attaching AuctionConfigs', error); - return bids; - } - } else { - return bids; - } + return bids; }, /** @@ -2044,15 +1991,6 @@ function getFormatCount(imp) { return formatCount; } -/** - * Checks if auction config is valid - * @param {object} config - * @returns bool - */ -function isValidAuctionConfig(config) { - return typeof config === 'object' && config !== null; -} - /** * Adds device.w / device.h info * @param {object} r diff --git a/modules/ixBidAdapter.md b/modules/ixBidAdapter.md index e6f6f8dc320..14a013fd6be 100644 --- a/modules/ixBidAdapter.md +++ b/modules/ixBidAdapter.md @@ -468,11 +468,6 @@ pbjs.setConfig({ The timeout value must be a positive whole number in milliseconds. -Protected Audience API (FLEDGE) -=========================== - -In order to enable receiving [Protected Audience API](https://developer.chrome.com/en/docs/privacy-sandbox/fledge/) traffic, follow Prebid's documentation on [paapiForGpt](https://docs.prebid.org/dev-docs/modules/paapiForGpt.html) module to build and enable Fledge. - Additional Information ====================== diff --git a/modules/jixieBidAdapter.js b/modules/jixieBidAdapter.js index 3a4df75762b..6fc6c86cfcc 100644 --- a/modules/jixieBidAdapter.js +++ b/modules/jixieBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {deepAccess, isArray, logWarn, isFn, isPlainObject, logError, logInfo, getWinDimensions} from '../src/utils.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; @@ -7,6 +6,7 @@ import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {ajax} from '../src/ajax.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {Renderer} from '../src/Renderer.js'; +import {getDNT} from '../libraries/dnt/index.js'; const ADAPTER_VERSION = '2.1.0'; const PREBID_VERSION = '$prebid.version$'; diff --git a/modules/jwplayerBidAdapter.js b/modules/jwplayerBidAdapter.js index 9ee7312bb84..7f2a3224819 100644 --- a/modules/jwplayerBidAdapter.js +++ b/modules/jwplayerBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; import { isArray, isFn, deepAccess, deepSetValue, logError, logWarn } from '../src/utils.js'; import { config } from '../src/config.js'; import { hasPurpose1Consent } from '../src/utils/gdpr.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'jwplayer'; const BASE_URL = 'https://vpb-server.jwplayer.com/'; diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 1909112d36d..ad70cf2e953 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -199,7 +199,6 @@ function buildRequests(validBidRequests, bidderRequest) { function interpretResponse(response, bidRequest) { const bids = response.body; - const fledgeAuctionConfigs = []; const bidResponses = []; if (isEmpty(bids) || typeof bids !== 'object') { @@ -241,23 +240,9 @@ function interpretResponse(response, bidRequest) { } bidResponses.push(bidResponse); - - if (adUnit.auctionConfig) { - fledgeAuctionConfigs.push({ - bidId: bidID, - config: adUnit.auctionConfig - }) - } } - if (fledgeAuctionConfigs.length > 0) { - return { - bids: bidResponses, - paapi: fledgeAuctionConfigs - } - } else { - return bidResponses; - } + return bidResponses; } function getUserSyncs(syncOptions, _, gdprConsent, usPrivacy, gppConsent) { diff --git a/modules/lemmaDigitalBidAdapter.js b/modules/lemmaDigitalBidAdapter.js index 7447d893217..227499424be 100644 --- a/modules/lemmaDigitalBidAdapter.js +++ b/modules/lemmaDigitalBidAdapter.js @@ -1,8 +1,8 @@ import * as utils from '../src/utils.js'; -import { getDNT } from '../libraries/dnt/index.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/lkqdBidAdapter.js b/modules/lkqdBidAdapter.js index 535dbbf759b..a017b3c2eb3 100644 --- a/modules/lkqdBidAdapter.js +++ b/modules/lkqdBidAdapter.js @@ -46,7 +46,6 @@ export const spec = { const DOMAIN = bid.params.pageurl || REFERER; const GDPR = BIDDER_GDPR || bid.params.gdpr || null; const GDPRS = BIDDER_GDPRS || bid.params.gdprs || null; - const DNT = bid.params.dnt || null; const BID_FLOOR = 0; const VIDEO_BID = bid.video ? bid.video : {}; @@ -76,10 +75,6 @@ export const spec = { } }; - if (isSet(DNT)) { - requestData.device.dnt = DNT; - } - if (isSet(config.getConfig('coppa'))) { requestData.regs.coppa = config.getConfig('coppa') === true ? 1 : 0; } diff --git a/modules/logicadBidAdapter.js b/modules/logicadBidAdapter.js index 64a848c157e..310513ab392 100644 --- a/modules/logicadBidAdapter.js +++ b/modules/logicadBidAdapter.js @@ -42,14 +42,6 @@ export const spec = { bids.push(seatbid.bid); }) - const fledgeAuctionConfigs = deepAccess(serverResponse, 'ext.fledgeAuctionConfigs') || []; - if (fledgeAuctionConfigs.length) { - return { - bids, - paapi: fledgeAuctionConfigs, - }; - } - return bids; }, getUserSyncs: function (syncOptions, serverResponses) { @@ -74,14 +66,6 @@ function newBidRequest(bidRequest, bidderRequest) { mediaTypes: bidRequest.mediaTypes, } - const fledgeEnabled = deepAccess(bidderRequest, 'paapi.enabled') - if (fledgeEnabled) { - const ae = deepAccess(bidRequest, 'ortb2Imp.ext.ae'); - if (ae) { - bid.ae = ae; - } - } - const data = { // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781 auctionId: bidRequest.auctionId, diff --git a/modules/luceadBidAdapter.js b/modules/luceadBidAdapter.js index 134b6e505eb..186002b77ba 100755 --- a/modules/luceadBidAdapter.js +++ b/modules/luceadBidAdapter.js @@ -106,34 +106,7 @@ function interpretResponse(serverResponse, bidRequest) { })); logInfo('interpretResponse', {serverResponse, bidRequest, bidRequestData, bids}); - - if (response?.enable_pa === false) { return bids; } - - const fledgeAuctionConfigs = (response.bids || []).map(bid => ({ - bidId: bid?.bid_id, - config: { - seller: baseUrl, - decisionLogicUrl: `${baseUrl}/js/ssp.js`, - interestGroupBuyers: [baseUrl], - requestedSize: bid?.size, - auctionSignals: { - size: bid?.size, - }, - perBuyerSignals: { - [baseUrl]: { - prebid_paapi: true, - prebid_bid_id: bid?.bid_id, - prebid_request_id: bidRequestData.request_id, - placement_id: bid.placement_id, - // floor, - is_sra: true, - endpoint_url: endpointUrl, - }, - } - } - })); - - return {bids, paapi: fledgeAuctionConfigs}; + return {bids}; } function report(type, data) { diff --git a/modules/marsmediaBidAdapter.js b/modules/marsmediaBidAdapter.js index 3a7039d7899..0224c951374 100644 --- a/modules/marsmediaBidAdapter.js +++ b/modules/marsmediaBidAdapter.js @@ -1,11 +1,11 @@ 'use strict'; -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, parseSizesInput, isArray, getWindowTop, deepSetValue, triggerPixel, getWindowSelf, isPlainObject } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import { percentInView } from '../libraries/percentInView/percentInView.js'; import {getMinSize} from '../libraries/sizeUtils/sizeUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; function MarsmediaAdapter() { this.code = 'marsmedia'; diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js index a1d333ab0af..a5a87fc80a1 100644 --- a/modules/mediaforceBidAdapter.js +++ b/modules/mediaforceBidAdapter.js @@ -1,9 +1,9 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, isStr, replaceAuctionPrice, triggerPixel, parseGPTSingleSizeArrayToRtbSize } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { buildNativeRequest, parseNativeResponse } from '../libraries/nativeAssetsUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/mediafuseBidAdapter.js b/modules/mediafuseBidAdapter.js index 0bffb9219ce..a2922c6cd3e 100644 --- a/modules/mediafuseBidAdapter.js +++ b/modules/mediafuseBidAdapter.js @@ -19,18 +19,17 @@ import { import {Renderer} from '../src/Renderer.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {getStorageManager} from '../src/storageManager.js'; import {bidderSettings} from '../src/bidderSettings.js'; import {hasPurpose1Consent} from '../src/utils/gdpr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; -import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import { getANKewyordParamFromMaps, getANKeywordParam } from '../libraries/appnexusUtils/anKeywords.js'; -import {convertCamelToUnderscore, fill} from '../libraries/appnexusUtils/anUtils.js'; +import {convertCamelToUnderscore} from '../libraries/appnexusUtils/anUtils.js'; import {chunk} from '../libraries/chunk/chunk.js'; /** @@ -222,10 +221,6 @@ export const spec = { const mfKeywords = config.getConfig('mediafuseAuctionKeywords'); payload.keywords = getANKeywordParam(bidderRequest?.ortb2, mfKeywords); - if (config.getConfig('adpod.brandCategoryExclusion')) { - payload.brand_category_uniqueness = true; - } - if (debugObjParams.enabled) { payload.debug = debugObjParams; logInfo('MediaFuse Debug Auction Settings:\n\n' + JSON.stringify(debugObjParams, null, 4)); @@ -261,16 +256,6 @@ export const spec = { payload.referrer_detection = refererinfo; } - const hasAdPodBid = ((bidRequests) || []).find(hasAdPod); - if (hasAdPodBid) { - bidRequests.filter(hasAdPod).forEach(adPodBid => { - const adPodTags = createAdPodRequest(tags, adPodBid); - // don't need the original adpod placement because it's in adPodTags - const nonPodTags = payload.tags.filter(tag => tag.uuid !== adPodBid.bidId); - payload.tags = [...nonPodTags, ...adPodTags]; - }); - } - if (bidRequests[0].userIdAsEids?.length > 0) { const eids = []; bidRequests[0].userIdAsEids.forEach(eid => { @@ -578,7 +563,7 @@ function newBid(serverBid, rtbBid, bidderRequest) { } if (rtbBid.rtb.video) { - // shared video properties used for all 3 contexts + // shared video properties used for both stream contexts Object.assign(bid, { width: rtbBid.rtb.video.player_width, height: rtbBid.rtb.video.player_height, @@ -588,17 +573,6 @@ function newBid(serverBid, rtbBid, bidderRequest) { const videoContext = deepAccess(bidRequest, 'mediaTypes.video.context'); switch (videoContext) { - case ADPOD: - const primaryCatId = (APPNEXUS_CATEGORY_MAPPING[rtbBid.brand_category_id]) ? APPNEXUS_CATEGORY_MAPPING[rtbBid.brand_category_id] : null; - bid.meta = Object.assign({}, bid.meta, { primaryCatId }); - const dealTier = rtbBid.deal_priority; - bid.video = { - context: ADPOD, - durationSeconds: Math.floor(rtbBid.rtb.video.duration_ms / 1000), - dealTier - }; - bid.vastUrl = rtbBid.rtb.video.asset_url; - break; case OUTSTREAM: bid.adResponse = serverBid; bid.adResponse.ad = bid.adResponse.ads[0]; @@ -755,11 +729,7 @@ function bidToTag(bid) { const videoMediaType = deepAccess(bid, `mediaTypes.${VIDEO}`); const context = deepAccess(bid, 'mediaTypes.video.context'); - if (videoMediaType && context === 'adpod') { - tag.hb_source = 7; - } else { - tag.hb_source = 1; - } + tag.hb_source = 1; if (bid.mediaType === VIDEO || videoMediaType) { tag.ad_types.push(VIDEO); } @@ -908,14 +878,6 @@ function hasDebug(bid) { return !!bid.debug } -function hasAdPod(bid) { - return ( - bid.mediaTypes && - bid.mediaTypes.video && - bid.mediaTypes.video.context === ADPOD - ); -} - function hasOmidSupport(bid) { let hasOmid = false; const bidderParams = bid.params; @@ -929,54 +891,6 @@ function hasOmidSupport(bid) { return hasOmid; } -/** - * Expand an adpod placement into a set of request objects according to the - * total adpod duration and the range of duration seconds. Sets minduration/ - * maxduration video property according to requireExactDuration configuration - */ -function createAdPodRequest(tags, adPodBid) { - const { durationRangeSec, requireExactDuration } = adPodBid.mediaTypes.video; - - const numberOfPlacements = getAdPodPlacementNumber(adPodBid.mediaTypes.video); - const maxDuration = Math.max(...durationRangeSec); - - const tagToDuplicate = tags.filter(tag => tag.uuid === adPodBid.bidId); - const request = fill(...tagToDuplicate, numberOfPlacements); - - if (requireExactDuration) { - const divider = Math.ceil(numberOfPlacements / durationRangeSec.length); - const chunked = chunk(request, divider); - - // each configured duration is set as min/maxduration for a subset of requests - durationRangeSec.forEach((duration, index) => { - chunked[index].forEach(tag => { - setVideoProperty(tag, 'minduration', duration); - setVideoProperty(tag, 'maxduration', duration); - }); - }); - } else { - // all maxdurations should be the same - request.forEach(tag => setVideoProperty(tag, 'maxduration', maxDuration)); - } - - return request; -} - -function getAdPodPlacementNumber(videoParams) { - const { adPodDurationSec, durationRangeSec, requireExactDuration } = videoParams; - const minAllowedDuration = Math.min(...durationRangeSec); - const numberOfPlacements = Math.floor(adPodDurationSec / minAllowedDuration); - - return requireExactDuration - ? Math.max(numberOfPlacements, durationRangeSec.length) - : numberOfPlacements; -} - -function setVideoProperty(tag, key, value) { - if (isEmpty(tag.video)) { tag.video = {}; } - tag.video[key] = value; -} - function getRtbBid(tag) { return tag && tag.ads && tag.ads.length && ((tag.ads) || []).find(ad => ad.rtb); } diff --git a/modules/mediakeysBidAdapter.js b/modules/mediakeysBidAdapter.js index a4eeb591d90..34159385cc7 100644 --- a/modules/mediakeysBidAdapter.js +++ b/modules/mediakeysBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { cleanObj, deepAccess, @@ -21,6 +20,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; +import {getDNT} from '../libraries/dnt/index.js'; const AUCTION_TYPE = 1; const BIDDER_CODE = 'mediakeys'; diff --git a/modules/medianetBidAdapter.js b/modules/medianetBidAdapter.js index cec3880a6d7..18a557c8617 100644 --- a/modules/medianetBidAdapter.js +++ b/modules/medianetBidAdapter.js @@ -256,9 +256,6 @@ function slotParams(bidRequest, bidderRequests) { if (floorInfo && floorInfo.length > 0) { params.bidfloors = floorInfo; } - if (bidderRequests.paapi?.enabled) { - params.ext.ae = bidRequest?.ortb2Imp?.ext?.ae; - } return params; } @@ -487,7 +484,7 @@ export const spec = { * Unpack the response from the server into a list of bids. * * @param {*} serverResponse A successful response from the server. - * @returns {{bids: *[], fledgeAuctionConfigs: *[]} | *[]} An object containing bids and fledgeAuctionConfigs if present, otherwise an array of bids. + * @returns {*[]} An array of bids. */ interpretResponse: function(serverResponse, request) { let validBids = []; @@ -502,18 +499,7 @@ export const spec = { validBids = bids.filter(bid => isValidBid(bid)); validBids.forEach(addRenderer); } - const fledgeAuctionConfigs = deepAccess(serverResponse, 'body.ext.paApiAuctionConfigs') || []; - const ortbAuctionConfigs = deepAccess(serverResponse, 'body.ext.igi') || []; - if (fledgeAuctionConfigs.length === 0 && ortbAuctionConfigs.length === 0) { - return validBids; - } - if (ortbAuctionConfigs.length > 0) { - fledgeAuctionConfigs.push(...ortbAuctionConfigs.map(({igs}) => igs || []).flat()); - } - return { - bids: validBids, - paapi: fledgeAuctionConfigs, - } + return validBids; }, getUserSyncs: function(syncOptions, serverResponses) { const cookieSyncUrls = fetchCookieSyncUrls(serverResponses); diff --git a/modules/medianetBidAdapter.md b/modules/medianetBidAdapter.md index 500c9f3f12b..1af49e5b6dc 100644 --- a/modules/medianetBidAdapter.md +++ b/modules/medianetBidAdapter.md @@ -181,23 +181,3 @@ var adUnits = [{ ``` - -# Protected Audience API (FLEDGE) - -In order to enable PAAPI auctions follow the instructions below: - -1. Add the paapiForGpt and paapi modules to your prebid bundle. -2. Add the following configuration for the module -``` -pbjs.que.push(function() { - pbjs.setConfig({ - paapi: { - enabled: true, - bidders: ['medianet'], - defaultForSlots: 1 - } - }); -}); -``` - -For a detailed guide to enabling PAAPI auctions follow Prebid's documentation on [paapiForGpt](https://docs.prebid.org/dev-docs/modules/paapiForGpt.html) diff --git a/modules/mgidBidAdapter.js b/modules/mgidBidAdapter.js index 8044768bdad..c74a3ba65b2 100644 --- a/modules/mgidBidAdapter.js +++ b/modules/mgidBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { _each, deepAccess, @@ -25,6 +24,7 @@ import { getStorageManager } from '../src/storageManager.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { getUserSyncs } from '../libraries/mgidUtils/mgidUtils.js' import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js' +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/mileBidAdapter.ts b/modules/mileBidAdapter.ts index f24feb8b74b..7271d8b0370 100644 --- a/modules/mileBidAdapter.ts +++ b/modules/mileBidAdapter.ts @@ -1,8 +1,8 @@ import { type BidderSpec, registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { deepAccess, deepSetValue, generateUUID, logInfo, logError } from '../src/utils.js'; -import { getDNT } from '../libraries/dnt/index.js'; import { ajax } from '../src/ajax.js'; +import { getDNT } from '../libraries/dnt/index.js'; /** * Mile Bid Adapter diff --git a/modules/nexverseBidAdapter.js b/modules/nexverseBidAdapter.js index 25d52000a82..91e78b807bd 100644 --- a/modules/nexverseBidAdapter.js +++ b/modules/nexverseBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import { isArray, generateUUID, getWinDimensions, isNumber } from '../src/utils.js'; @@ -9,6 +8,7 @@ import { getDeviceModel, buildEndpointUrl, isBidRequestValid, parseNativeRespons import {getStorageManager} from '../src/storageManager.js'; import {MODULE_TYPE_UID} from '../src/activities/modules.js'; import { config } from '../src/config.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'nexverse'; const BIDDER_ENDPOINT = 'https://rtb.nexverse.ai'; diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index d919d1398b7..827291f5407 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -145,7 +145,7 @@ function buildRequests(validBidRequests, bidderRequest) { const connection = getConnectionInfo(); payload.networkConnectionType = connection?.type || null; payload.networkEffectiveConnectionType = connection?.effectiveType || null; - payload.fledgeEnabled = Boolean(bidderRequest?.paapi?.enabled) + payload.fledgeEnabled = false; return { method: 'POST', url: ENDPOINT, @@ -160,7 +160,7 @@ function interpretResponse(serverResponse, bidderRequest) { if (!body || (body.nobid && body.nobid === true)) { return bids; } - if (!body.fledgeAuctionConfigs && (!body.bids || !Array.isArray(body.bids) || body.bids.length === 0)) { + if (!body.bids || !Array.isArray(body.bids) || body.bids.length === 0) { return bids; } Array.isArray(body.bids) && body.bids.forEach(bid => { @@ -206,15 +206,7 @@ function interpretResponse(serverResponse, bidderRequest) { bids.push(responseBid); }); - if (body.fledgeAuctionConfigs && Array.isArray(body.fledgeAuctionConfigs)) { - const fledgeAuctionConfigs = body.fledgeAuctionConfigs - return { - bids, - paapi: fledgeAuctionConfigs - } - } else { - return bids; - } + return bids; } function createRenderer(bid, rendererOptions = {}) { diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index 2da04ad3e38..c84414c9202 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -61,9 +61,7 @@ const converter = ortbConverter({ if (bid.params.coppa) { utils.deepSetValue(req, 'regs.coppa', 1); } - if (bid.params.doNotTrack) { - utils.deepSetValue(req, 'device.dnt', 1); - } + utils.deepSetValue(req, 'device.dnt', 0); if (bid.params.platform) { utils.deepSetValue(req, 'ext.platform', bid.params.platform); } @@ -98,27 +96,7 @@ const converter = ortbConverter({ utils.deepSetValue(ortbResponse, 'ext.platform', ortbRequest.ext.platform); } } - const response = buildResponse(bidResponses, ortbResponse, context); - // TODO: we may want to standardize this and move fledge logic to ortbConverter - let fledgeAuctionConfigs = utils.deepAccess(ortbResponse, 'ext.fledge_auction_configs'); - if (fledgeAuctionConfigs) { - fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { - return { - bidId, - config: mergeDeep(Object.assign({}, cfg), { - auctionSignals: { - ortb2Imp: context.impContext[bidId]?.imp, - }, - }), - } - }); - return { - bids: response.bids, - paapi: fledgeAuctionConfigs, - } - } else { - return response - } + return buildResponse(bidResponses, ortbResponse, context); }, overrides: { imp: { diff --git a/modules/operaadsBidAdapter.js b/modules/operaadsBidAdapter.js index 8645196d07d..201ecfb8540 100644 --- a/modules/operaadsBidAdapter.js +++ b/modules/operaadsBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, deepSetValue, @@ -17,6 +16,7 @@ import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {Renderer} from '../src/Renderer.js'; import {OUTSTREAM} from '../src/video.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/optableBidAdapter.js b/modules/optableBidAdapter.js deleted file mode 100644 index d2dae252e6c..00000000000 --- a/modules/optableBidAdapter.js +++ /dev/null @@ -1,67 +0,0 @@ -import * as utils from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { config } from '../src/config.js'; -import { BANNER } from '../src/mediaTypes.js'; -import { ortbConverter } from '../libraries/ortbConverter/converter.js' -const converter = ortbConverter({ - context: { netRevenue: true, ttl: 300 }, - imp(buildImp, bidRequest, context) { - const imp = buildImp(bidRequest, context); - utils.mergeDeep(imp, { - tagid: bidRequest.params.site, - }); - return imp; - } -}); -const BIDDER_CODE = 'optable'; -const DEFAULT_REGION = 'ca' -const DEFAULT_ORIGIN = 'https://ads.optable.co' - -function getOrigin() { - return config.getConfig('optable.origin') ?? DEFAULT_ORIGIN; -} - -function getBaseUrl() { - const region = config.getConfig('optable.region') ?? DEFAULT_REGION; - return `${getOrigin()}/${region}` -} - -export const spec = { - code: BIDDER_CODE, - isBidRequestValid: function(bid) { return !!bid.params?.site }, - buildRequests: function(bidRequests, bidderRequest) { - const requestURL = `${getBaseUrl()}/ortb2/v1/ssp/bid` - const data = converter.toORTB({ bidRequests, bidderRequest, context: { mediaType: BANNER } }); - return { method: 'POST', url: requestURL, data } - }, - buildPAAPIConfigs: function(bidRequests) { - const origin = getOrigin(); - return bidRequests - .filter(req => req.ortb2Imp?.ext?.ae) - .map(bid => ({ - bidId: bid.bidId, - config: { - seller: origin, - decisionLogicURL: `${getBaseUrl()}/paapi/v1/ssp/decision-logic.js?origin=${bid.params.site}`, - interestGroupBuyers: [origin], - perBuyerMultiBidLimits: { - [origin]: 100 - }, - perBuyerCurrencies: { - [origin]: 'USD' - } - } - })) - }, - interpretResponse: function(response, request) { - const bids = converter.fromORTB({ response: response.body, request: request.data }).bids - const auctionConfigs = (response.body.ext?.optable?.fledge?.auctionconfigs ?? []).map((cfg) => { - const { impid, ...config } = cfg; - return { bidId: impid, config } - }) - - return { bids, paapi: auctionConfigs } - }, - supportedMediaTypes: [BANNER] -} -registerBidder(spec); diff --git a/modules/optableBidAdapter.md b/modules/optableBidAdapter.md deleted file mode 100644 index a7c4829fe63..00000000000 --- a/modules/optableBidAdapter.md +++ /dev/null @@ -1,41 +0,0 @@ -# Overview - -``` -Module Name: Optable Bidder Adapter -Module Type: Bidder Adapter -Maintainer: prebid@optable.co -``` - -# Description - -Module that connects to Optable's demand sources. - -# Bid Parameters -## Banner - -| Name | Scope | Type | Description | Example -| ---- | ----- | ---- | ----------- | ------- -| `site` | required | String | Optable site ID provided by your Optable representative. | "aaaaaaaa" - -## Video - -Not supported at the moment. - -# Example -```javascript -var adUnits = [ - { - code: 'test-div', - sizes: [[728, 90]], // a display size - mediaTypes: {'banner': {}}, - bids: [ - { - bidder: 'optable', - params: { - site: 'aaaaaaaa', - }, - }, - ], - }, -]; -``` diff --git a/modules/ozoneBidAdapter.js b/modules/ozoneBidAdapter.js index e804eef164e..027d623ba12 100644 --- a/modules/ozoneBidAdapter.js +++ b/modules/ozoneBidAdapter.js @@ -1,21 +1,24 @@ import { - logInfo, - logError, deepAccess, - logWarn, + deepClone, deepSetValue, + generateUUID, + getBidIdParameter, isArray, + logError, + logInfo, + logWarn, mergeDeep, - parseUrl, - generateUUID, isInteger, deepClone, getBidIdParameter + parseUrl } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {getPriceBucketString} from '../src/cpmBucketManager.js'; -import { Renderer } from '../src/Renderer.js'; +import {Renderer} from '../src/Renderer.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {toOrtb25} from '../libraries/ortb2.5Translator/translator.js'; + const BIDDER_CODE = 'ozone'; const ORIGIN = 'https://elb.the-ozone-project.com'; const AUCTIONURI = '/openrtb2/auction'; @@ -137,7 +140,6 @@ export const spec = { if (this.blockTheRequest()) { return []; } - const fledgeEnabled = !!bidderRequest.fledgeEnabled; let htmlParams = {'publisherId': '', 'siteId': ''}; if (validBidRequests.length > 0) { Object.assign(this.cookieSyncBag.userIdObject, this.findAllUserIdsFromEids(validBidRequests[0])); @@ -274,14 +276,6 @@ export const spec = { if (auctionId) { obj.ext.auctionId = auctionId; } - if (fledgeEnabled) { - const auctionEnvironment = deepAccess(ozoneBidRequest, 'ortb2Imp.ext.ae'); - if (isInteger(auctionEnvironment)) { - deepSetValue(obj, 'ext.ae', auctionEnvironment); - } else { - logError(`ignoring ortb2Imp.ext.ae - not an integer for obj.id=${obj.id}`); - } - } return obj; }); const extObj = {}; @@ -572,20 +566,6 @@ export const spec = { } } let ret = arrAllBids; - let fledgeAuctionConfigs = deepAccess(serverResponse, 'ext.igi') || []; - if (isArray(fledgeAuctionConfigs) && fledgeAuctionConfigs.length > 0) { - fledgeAuctionConfigs = fledgeAuctionConfigs.filter(cfg => { - if (typeof cfg !== 'object' || cfg === null) { - logWarn('Removing malformed fledge auction config:', cfg); - return false; - } - return true; - }); - ret = { - bids: arrAllBids, - fledgeAuctionConfigs, - }; - } const endTime = new Date().getTime(); logInfo(`interpretResponse going to return at time ${endTime} (took ${endTime - startTime}ms) Time from buildRequests Start -> interpretRequests End = ${endTime - this.propertyBag.buildRequestsStart}ms`); logInfo('will return: ', deepClone(ret)); diff --git a/modules/paapi.js b/modules/paapi.js deleted file mode 100644 index e67b24bdcfc..00000000000 --- a/modules/paapi.js +++ /dev/null @@ -1,808 +0,0 @@ -/** - * Collect PAAPI component auction configs from bid adapters and make them available through `pbjs.getPAAPIConfig()` - */ -import {config} from '../src/config.js'; -import {getHook, hook, module} from '../src/hook.js'; -import { - deepAccess, - deepEqual, - deepSetValue, - logError, - logInfo, - logWarn, - mergeDeep, - sizesToSizeTuples -} from '../src/utils.js'; -import {IMP, PBS, registerOrtbProcessor, RESPONSE} from '../src/pbjsORTB.js'; -import * as events from '../src/events.js'; -import {EVENTS} from '../src/constants.js'; -import {currencyCompare} from '../libraries/currencyUtils/currency.js'; -import {keyCompare, maximum, minimum} from '../src/utils/reducers.js'; -import {getGlobal} from '../src/prebidGlobal.js'; -import {auctionStore} from '../libraries/weakStore/weakStore.js'; -import {adapterMetrics, guardTids} from '../src/adapters/bidderFactory.js'; -import {defer, PbPromise} from '../src/utils/promise.js'; -import {auctionManager} from '../src/auctionManager.js'; - -const MODULE = 'PAAPI'; - -const submodules = []; -const USED = new WeakSet(); - -export function registerSubmodule(submod) { - submodules.push(submod); - submod.init && submod.init({ - getPAAPIConfig, - expandFilters - }); -} - -module('paapi', registerSubmodule); - -/* auction configs as returned by getPAAPIConfigs */ -const configsForAuction = auctionStore(); - -/* auction configs returned by adapters, but waiting for end-of-auction signals before they're added to configsForAuction */ -const pendingConfigsForAuction = auctionStore(); - -/* igb returned by adapters, waiting for end-of-auction signals before they're merged into configForAuctions */ -const pendingBuyersForAuction = auctionStore(); - -/* for auction configs that were generated in parallel with auctions (and contain promises), their resolve/reject methods */ -const deferredConfigsForAuction = auctionStore(); - -let latestAuctionForAdUnit = {}; -let moduleConfig = {}; - -config.getConfig('paapi', config => { - init(config.paapi); -}); - -export function reset() { - submodules.splice(0, submodules.length); - latestAuctionForAdUnit = {}; -} - -export function init(cfg) { - if (cfg && cfg.enabled === true) { - if (!moduleConfig.enabled) { - attachHandlers(); - } - moduleConfig = cfg; - logInfo(`${MODULE} enabled (browser ${isFledgeSupported() ? 'supports' : 'does NOT support'} runAdAuction)`, cfg); - } else { - if (moduleConfig.enabled) { - detachHandlers(); - } - moduleConfig = {}; - logInfo(`${MODULE} disabled`, cfg); - } -} - -function attachHandlers() { - getHook('addPaapiConfig').before(addPaapiConfigHook); - getHook('makeBidRequests').before(addPaapiData); - getHook('makeBidRequests').after(markForFledge); - getHook('processBidderRequests').before(parallelPaapiProcessing, 9); - // resolve params before parallel processing - getHook('processBidderRequests').before(buildPAAPIParams, 10); - getHook('processBidderRequests').before(adAuctionHeadersHook); - events.on(EVENTS.AUCTION_INIT, onAuctionInit); - events.on(EVENTS.AUCTION_END, onAuctionEnd); -} - -function detachHandlers() { - getHook('addPaapiConfig').getHooks({hook: addPaapiConfigHook}).remove(); - getHook('makeBidRequests').getHooks({hook: addPaapiData}).remove(); - getHook('makeBidRequests').getHooks({hook: markForFledge}).remove(); - getHook('processBidderRequests').getHooks({hook: parallelPaapiProcessing}).remove(); - getHook('processBidderRequests').getHooks({hook: buildPAAPIParams}).remove(); - getHook('processBidderRequests').getHooks({hook: adAuctionHeadersHook}).remove(); - events.off(EVENTS.AUCTION_INIT, onAuctionInit); - events.off(EVENTS.AUCTION_END, onAuctionEnd); -} - -export function adAuctionHeadersHook(next, spec, bids, bidderRequest, ajax, ...args) { - if (bidderRequest.paapi?.enabled) { - ajax = ((orig) => { - return function (url, callback, data, options) { - options = options ?? {}; - options.adAuctionHeaders = options.adAuctionHeaders ?? true; - return orig.call(this, url, callback, data, options); - } - })(ajax); - } - return next.call(this, spec, bids, bidderRequest, ajax, ...args); -} - -function getStaticSignals(adUnit = {}) { - const cfg = {}; - const requestedSize = getRequestedSize(adUnit); - if (requestedSize) { - cfg.requestedSize = requestedSize; - } - return cfg; -} - -function getSlotSignals(bidsReceived = [], bidRequests = []) { - let bidfloor, bidfloorcur; - if (bidsReceived.length > 0) { - const bestBid = bidsReceived.reduce(maximum(currencyCompare(bid => [bid.cpm, bid.currency]))); - bidfloor = bestBid.cpm; - bidfloorcur = bestBid.currency; - } else { - const floors = bidRequests.map(bid => typeof bid.getFloor === 'function' && bid.getFloor()).filter(f => f); - const minFloor = floors.length && floors.reduce(minimum(currencyCompare(floor => [floor.floor, floor.currency]))); - bidfloor = minFloor?.floor; - bidfloorcur = minFloor?.currency; - } - const cfg = {}; - if (bidfloor) { - deepSetValue(cfg, 'auctionSignals.prebid.bidfloor', bidfloor); - bidfloorcur && deepSetValue(cfg, 'auctionSignals.prebid.bidfloorcur', bidfloorcur); - } - return cfg; -} - -export function buyersToAuctionConfigs(igbRequests, merge = mergeBuyers, config = moduleConfig?.componentSeller ?? {}, partitioners = { - compact: (igbRequests) => partitionBuyers(igbRequests.map(req => req[1])).map(part => [{}, part]), - expand: partitionBuyersByBidder -}) { - if (!config.auctionConfig) { - logWarn(MODULE, 'Cannot use IG buyers: paapi.componentSeller.auctionConfig not set', igbRequests.map(req => req[1])); - return []; - } - const partition = partitioners[config.separateAuctions ? 'expand' : 'compact']; - return partition(igbRequests) - .map(([request, igbs]) => { - const auctionConfig = mergeDeep(merge(igbs), config.auctionConfig); - auctionConfig.auctionSignals = setFPD(auctionConfig.auctionSignals || {}, request); - return [request, auctionConfig]; - }); -} - -function onAuctionEnd({auctionId, bidsReceived, bidderRequests, adUnitCodes, adUnits}) { - const adUnitsByCode = Object.fromEntries(adUnits?.map(au => [au.code, au]) || []); - const allReqs = bidderRequests?.flatMap(br => br.bids); - const paapiConfigs = configsForAuction(auctionId); - (adUnitCodes || []).forEach(au => { - if (!paapiConfigs.hasOwnProperty(au)) { - paapiConfigs[au] = null; - } - !latestAuctionForAdUnit.hasOwnProperty(au) && (latestAuctionForAdUnit[au] = null); - }); - - const pendingConfigs = pendingConfigsForAuction(auctionId); - const pendingBuyers = pendingBuyersForAuction(auctionId); - - if (pendingConfigs && pendingBuyers) { - Object.entries(pendingBuyers).forEach(([adUnitCode, igbRequests]) => { - buyersToAuctionConfigs(igbRequests).forEach(([{bidder}, auctionConfig]) => append(pendingConfigs, adUnitCode, {id: getComponentSellerConfigId(bidder), config: auctionConfig})) - }) - } - - const deferredConfigs = deferredConfigsForAuction(auctionId); - - const adUnitsWithConfigs = Array.from(new Set(Object.keys(pendingConfigs).concat(Object.keys(deferredConfigs)))); - const signals = Object.fromEntries( - adUnitsWithConfigs.map(adUnitCode => { - latestAuctionForAdUnit[adUnitCode] = auctionId; - const forThisAdUnit = (bid) => bid.adUnitCode === adUnitCode; - return [adUnitCode, { - ...getStaticSignals(adUnitsByCode[adUnitCode]), - ...getSlotSignals(bidsReceived?.filter(forThisAdUnit), allReqs?.filter(forThisAdUnit)) - }] - }) - ) - - const configsById = {}; - Object.entries(pendingConfigs || {}).forEach(([adUnitCode, auctionConfigs]) => { - auctionConfigs.forEach(({id, config}) => append(configsById, id, { - adUnitCode, - config: mergeDeep({}, signals[adUnitCode], config) - })); - }); - - function resolveSignals(signals, deferrals) { - Object.entries(deferrals).forEach(([signal, {resolve, default: defaultValue}]) => { - let value = signals.hasOwnProperty(signal) ? signals[signal] : null; - if (value == null && defaultValue == null) { - value = undefined; - } else if (typeof defaultValue === 'object' && typeof value === 'object') { - value = mergeDeep({}, defaultValue, value); - } else { - value = value ?? defaultValue - } - resolve(value); - }) - } - - Object.entries(deferredConfigs).forEach(([adUnitCode, {top, components}]) => { - resolveSignals(signals[adUnitCode], top); - Object.entries(components).forEach(([configId, {deferrals}]) => { - const matchingConfigs = configsById.hasOwnProperty(configId) ? configsById[configId] : []; - if (matchingConfigs.length > 1) { - logWarn(`Received multiple PAAPI configs for the same bidder and seller (${configId}), active PAAPI auctions will only see the first`); - } - const {config} = matchingConfigs.shift() ?? {config: {...signals[adUnitCode]}} - resolveSignals(config, deferrals); - }) - }); - - const newConfigs = Object.values(configsById).flatMap(configs => configs); - const hasDeferredConfigs = Object.keys(deferredConfigs).length > 0; - - if (moduleConfig.parallel && hasDeferredConfigs && newConfigs.length > 0) { - logError(`Received PAAPI configs after PAAPI auctions were already started in parallel with their contextual auction`, newConfigs) - } - - newConfigs.forEach(({adUnitCode, config}) => { - if (paapiConfigs[adUnitCode] == null) { - paapiConfigs[adUnitCode] = { - ...signals[adUnitCode], - componentAuctions: [] - } - } - paapiConfigs[adUnitCode].componentAuctions.push(mergeDeep({}, signals[adUnitCode], config)); - }); - - if (!moduleConfig.parallel || !hasDeferredConfigs) { - submodules.forEach(submod => submod.onAuctionConfig?.(auctionId, paapiConfigs)); - } -} - -function append(target, key, value) { - !target.hasOwnProperty(key) && (target[key] = []); - target[key].push(value); -} - -function setFPD(target, {ortb2, ortb2Imp}) { - ortb2 != null && deepSetValue(target, 'prebid.ortb2', mergeDeep({}, ortb2, target.prebid?.ortb2)); - ortb2Imp != null && deepSetValue(target, 'prebid.ortb2Imp', mergeDeep({}, ortb2Imp, target.prebid?.ortb2Imp)); - return target; -} - -function getConfigId(bidderCode, seller) { - return `${bidderCode}::${seller}`; -} - -function getComponentSellerConfigId(bidderCode) { - return moduleConfig.componentSeller.separateAuctions ? `igb::${bidderCode}` : 'igb'; -} - -export function addPaapiConfigHook(next, request, paapiConfig) { - if (getFledgeConfig(config.getCurrentBidder()).enabled) { - const {adUnitCode, auctionId, bidder} = request; - - function storePendingData(store, data) { - const target = store(auctionId); - if (target != null) { - append(target, adUnitCode, data) - } else { - logWarn(MODULE, `Received PAAPI config for auction that has closed (auction '${auctionId}', adUnit '${adUnitCode}')`, data); - } - } - - const {config, igb} = paapiConfig; - if (config) { - config.auctionSignals = setFPD(config.auctionSignals || {}, request); - const pbs = config.perBuyerSignals = config.perBuyerSignals ?? {}; - (config.interestGroupBuyers || []).forEach(buyer => { - pbs[buyer] = setFPD(pbs[buyer] ?? {}, request); - }) - storePendingData(pendingConfigsForAuction, {id: getConfigId(bidder, config.seller), config}); - } - if (igb && checkOrigin(igb)) { - igb.pbs = setFPD(igb.pbs || {}, request); - storePendingData(pendingBuyersForAuction, [request, igb]) - } - } - next(request, paapiConfig); -} - -export const IGB_TO_CONFIG = { - cur: 'perBuyerCurrencies', - pbs: 'perBuyerSignals', - ps: 'perBuyerPrioritySignals', - maxbid: 'auctionSignals.prebid.perBuyerMaxbid', -} - -function checkOrigin(igb) { - if (igb.origin) return true; - logWarn('PAAPI buyer does not specify origin and will be ignored', igb); -} - -/** - * Convert a list of InterestGroupBuyer (igb) objects into a partial auction config. - * https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/Protected%20Audience%20Support.md - */ -export function mergeBuyers(igbs) { - const buyers = new Set(); - return Object.assign( - igbs.reduce((config, igb) => { - if (checkOrigin(igb)) { - if (!buyers.has(igb.origin)) { - buyers.add(igb.origin); - Object.entries(IGB_TO_CONFIG).forEach(([igbField, configField]) => { - if (igb[igbField] != null) { - const entry = deepAccess(config, configField) || {} - entry[igb.origin] = igb[igbField]; - deepSetValue(config, configField, entry); - } - }); - } else { - logWarn(MODULE, `Duplicate buyer: ${igb.origin}. All but the first will be ignored`, igbs); - } - } - return config; - }, {}), - { - interestGroupBuyers: Array.from(buyers.keys()) - } - ); -} - -/** - * Partition a list of InterestGroupBuyer (igb) object into sets that can each be merged into a single auction. - * If the same buyer (origin) appears more than once, it will be split across different partition unless the igb objects - * are identical. - */ -export function partitionBuyers(igbs) { - return igbs.reduce((partitions, igb) => { - if (checkOrigin(igb)) { - let partition = partitions.find(part => !part.hasOwnProperty(igb.origin) || deepEqual(part[igb.origin], igb)); - if (!partition) { - partition = {}; - partitions.push(partition); - } - partition[igb.origin] = igb; - } - return partitions; - }, []).map(part => Object.values(part)); -} - -export function partitionBuyersByBidder(igbRequests) { - const requests = {}; - const igbs = {}; - igbRequests.forEach(([request, igb]) => { - !requests.hasOwnProperty(request.bidder) && (requests[request.bidder] = request); - append(igbs, request.bidder, igb); - }) - return Object.entries(igbs).map(([bidder, igbs]) => [requests[bidder], igbs]) -} - -/** - * Expand PAAPI api filters into a map from ad unit code to auctionId. - * - * auctionId when specified, the result will have this as the value for each entry. - * when not specified, each ad unit will map to the latest auction that involved that ad unit. - * adUnitCode when specified, the result will contain only one entry (for this ad unit) or be empty (if this ad - * unit was never involved in an auction). - * when not specified, the result will contain an entry for every ad unit that was involved in any auction. - * @return {{[adUnitCode: string]: string}} - */ -function expandFilters({auctionId, adUnitCode} = {}) { - let adUnitCodes = []; - if (adUnitCode == null) { - adUnitCodes = Object.keys(latestAuctionForAdUnit); - } else if (latestAuctionForAdUnit.hasOwnProperty(adUnitCode)) { - adUnitCodes = [adUnitCode]; - } - return Object.fromEntries( - adUnitCodes.map(au => [au, auctionId ?? latestAuctionForAdUnit[au]]) - ); -} - -/** - * Get PAAPI auction configuration. - * - * @param {Object} [filters] - Filters object - * @param {string} [filters.auctionId] optional auction filter; if omitted, the latest auction for each ad unit is used - * @param {string} [filters.adUnitCode] optional ad unit filter - * @param {boolean} [includeBlanks=false] if true, include null entries for ad units that match the given filters but do not have any available auction configs. - * @returns {Object} a map from ad unit code to auction config for the ad unit. - */ -export function getPAAPIConfig(filters = {}, includeBlanks = false) { - const output = {}; - Object.entries(expandFilters(filters)).forEach(([au, auctionId]) => { - const auctionConfigs = configsForAuction(auctionId); - if (auctionConfigs?.hasOwnProperty(au)) { - // ad unit was involved in a PAAPI auction - const candidate = auctionConfigs[au]; - if (candidate && !USED.has(candidate)) { - output[au] = candidate; - USED.add(candidate); - } else if (includeBlanks) { - output[au] = null; - } - } else if (auctionId == null && includeBlanks) { - // ad unit was involved in a non-PAAPI auction - output[au] = null; - } - }); - return output; -} - -getGlobal().getPAAPIConfig = (filters) => getPAAPIConfig(filters); - -function isFledgeSupported() { - return 'runAdAuction' in navigator && 'joinAdInterestGroup' in navigator; -} - -function getFledgeConfig(bidder) { - const enabled = moduleConfig.enabled && (bidder == null || !moduleConfig.bidders?.length || moduleConfig.bidders?.includes(bidder)); - return { - enabled, - ae: enabled ? moduleConfig.defaultForSlots : undefined - }; -} - -/** - * Given an array of size tuples, return the one that should be used for PAAPI. - */ -export const getPAAPISize = hook('sync', function (sizes) { - sizes = sizes - ?.filter(([w, h]) => !(w === h && w <= 5)); - - if (sizes?.length) { - return sizes - .reduce(maximum(keyCompare(([w, h]) => w * h))); - } -}, 'getPAAPISize'); - -function getRequestedSize(adUnit) { - return adUnit.ortb2Imp?.ext?.paapi?.requestedSize || (() => { - const size = getPAAPISize(sizesToSizeTuples(adUnit.mediaTypes?.banner?.sizes)); - if (size) { - return { - width: size[0], - height: size[1] - }; - } - })(); -} - -export function addPaapiData(next, adUnits, ...args) { - if (isFledgeSupported() && moduleConfig.enabled) { - adUnits.forEach(adUnit => { - // https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/extensions/community_extensions/Protected%20Audience%20Support.md - const igsAe = adUnit.ortb2Imp?.ext?.igs != null - ? adUnit.ortb2Imp.ext.igs.ae || 1 - : null; - const extAe = adUnit.ortb2Imp?.ext?.ae; - if (igsAe !== extAe && igsAe != null && extAe != null) { - logWarn(MODULE, `Ad unit defines conflicting ortb2Imp.ext.ae and ortb2Imp.ext.igs, using the latter`, adUnit); - } - const ae = igsAe ?? extAe ?? moduleConfig.defaultForSlots; - if (ae) { - deepSetValue(adUnit, 'ortb2Imp.ext.ae', ae); - adUnit.ortb2Imp.ext.igs = Object.assign({ - ae: ae, - biddable: 1 - }, adUnit.ortb2Imp.ext.igs); - const requestedSize = getRequestedSize(adUnit); - if (requestedSize) { - deepSetValue(adUnit, 'ortb2Imp.ext.paapi.requestedSize', requestedSize); - } - adUnit.bids.forEach(bidReq => { - if (!getFledgeConfig(bidReq.bidder).enabled) { - deepSetValue(bidReq, 'ortb2Imp.ext.ae', 0); - bidReq.ortb2Imp.ext.igs = {ae: 0, biddable: 0}; - } - }) - } - }) - } - next(adUnits, ...args); -} - -export const NAVIGATOR_APIS = ['createAuctionNonce', 'getInterestGroupAdAuctionData']; - -export function markForFledge(next, bidderRequests) { - if (isFledgeSupported()) { - bidderRequests.forEach((bidderReq) => { - const {enabled} = getFledgeConfig(bidderReq.bidderCode); - Object.assign(bidderReq, { - paapi: { - enabled, - componentSeller: !!moduleConfig.componentSeller?.auctionConfig - } - }); - if (enabled) { - NAVIGATOR_APIS.forEach(method => { - bidderReq.paapi[method] = (...args) => new AsyncPAAPIParam(() => navigator[method](...args)) - }) - } - }); - } - next(bidderRequests); -} - -export const ASYNC_SIGNALS = [ - 'auctionSignals', - 'sellerSignals', - 'perBuyerSignals', - 'perBuyerTimeouts', - 'directFromSellerSignals', - 'perBuyerCurrencies', - 'perBuyerCumulativeTimeouts', - 'serverResponse' -]; - -const validatePartialConfig = (() => { - const REQUIRED_SYNC_SIGNALS = [ - { - props: ['seller'], - validate: (val) => typeof val === 'string' - }, - { - props: ['interestGroupBuyers'], - validate: (val) => Array.isArray(val) && val.length > 0 - }, - { - props: ['decisionLogicURL', 'decisionLogicUrl'], - validate: (val) => typeof val === 'string' - } - ]; - - return function (config) { - const invalid = REQUIRED_SYNC_SIGNALS.find(({props, validate}) => props.every(prop => !config.hasOwnProperty(prop) || !config[prop] || !validate(config[prop]))); - if (invalid) { - logError(`Partial PAAPI config has missing or invalid property "${invalid.props[0]}"`, config) - return false; - } - return true; - } -})() - -function callAdapterApi(spec, method, bids, bidderRequest) { - const metrics = adapterMetrics(bidderRequest); - const tidGuard = guardTids(bidderRequest); - let result; - metrics.measureTime(method, () => { - try { - result = spec[method](bids.map(tidGuard.bidRequest), tidGuard.bidderRequest(bidderRequest)) - } catch (e) { - logError(`Error invoking "${method}":`, e); - } - }); - return result; -} - -/** - * Adapters can provide a `spec.buildPAAPIConfigs(validBidRequests, bidderRequest)` to be included in PAAPI auctions - * that can be started in parallel with contextual auctions. - * - * If PAAPI is enabled, and an adapter provides `buildPAAPIConfigs`, it is invoked just before `buildRequests`, - * and takes the same arguments. It should return an array of PAAPI configuration objects with the same format - * as in `interpretResponse` (`{bidId, config?, igb?}`). - * - * Everything returned by `buildPAAPIConfigs` is treated in the same way as if it was returned by `interpretResponse` - - * except for signals that can be provided asynchronously (cfr. `ASYNC_SIGNALS`), which are replaced by promises. - * When the (contextual) auction ends, the promises are resolved. - * - * If during the auction the adapter's `interpretResponse` returned matching configurations (same `bidId`, - * and a `config` with the same `seller`, or an `igb` with the same `origin`), the promises resolve to their contents. - * Otherwise, they resolve to the values provided by `buildPAAPIConfigs`, or an empty object if no value was provided. - * - * Promisified auction configs are available from `getPAAPIConfig` immediately after `requestBids`. - * If the `paapi.parallel` config flag is set, PAAPI submodules are also triggered at the same time - * (instead of when the auction ends). - */ -export function parallelPaapiProcessing(next, spec, bids, bidderRequest, ...args) { - function makeDeferrals(defaults = {}) { - const promises = {}; - const deferrals = Object.fromEntries(ASYNC_SIGNALS.map(signal => { - const def = defer({promiseFactory: (resolver) => new Promise(resolver)}); - def.default = defaults.hasOwnProperty(signal) ? defaults[signal] : null; - promises[signal] = def.promise; - return [signal, def] - })) - return [deferrals, promises]; - } - - const {auctionId, paapi: {enabled, componentSeller} = {}} = bidderRequest; - const auctionConfigs = configsForAuction(auctionId); - bids.map(bid => bid.adUnitCode).forEach(adUnitCode => { - latestAuctionForAdUnit[adUnitCode] = auctionId; - if (!auctionConfigs.hasOwnProperty(adUnitCode)) { - auctionConfigs[adUnitCode] = null; - } - }); - - if (enabled && spec.buildPAAPIConfigs) { - const partialConfigs = callAdapterApi(spec, 'buildPAAPIConfigs', bids, bidderRequest) - const requestsById = Object.fromEntries(bids.map(bid => [bid.bidId, bid])); - (partialConfigs ?? []).forEach(({bidId, config, igb}) => { - const bidRequest = requestsById.hasOwnProperty(bidId) && requestsById[bidId]; - if (!bidRequest) { - logError(`Received partial PAAPI config for unknown bidId`, {bidId, config}); - } else { - const adUnitCode = bidRequest.adUnitCode; - latestAuctionForAdUnit[adUnitCode] = auctionId; - const deferredConfigs = deferredConfigsForAuction(auctionId); - - const getDeferredConfig = () => { - if (!deferredConfigs.hasOwnProperty(adUnitCode)) { - const [deferrals, promises] = makeDeferrals(); - auctionConfigs[adUnitCode] = { - ...getStaticSignals(auctionManager.index.getAdUnit(bidRequest)), - ...promises, - componentAuctions: [] - } - deferredConfigs[adUnitCode] = { - top: deferrals, - components: {}, - auctionConfig: auctionConfigs[adUnitCode] - } - } - return deferredConfigs[adUnitCode]; - } - - if (config && validatePartialConfig(config)) { - const configId = getConfigId(bidRequest.bidder, config.seller); - const deferredConfig = getDeferredConfig(); - if (deferredConfig.components.hasOwnProperty(configId)) { - logWarn(`Received multiple PAAPI configs for the same bidder and seller; config will be ignored`, { - config, - bidder: bidRequest.bidder - }) - } else { - const [deferrals, promises] = makeDeferrals(config); - const auctionConfig = { - ...getStaticSignals(bidRequest), - ...config, - ...promises - } - deferredConfig.auctionConfig.componentAuctions.push(auctionConfig) - deferredConfig.components[configId] = {auctionConfig, deferrals}; - } - } - if (componentSeller && igb && checkOrigin(igb)) { - const configId = getComponentSellerConfigId(spec.code); - const deferredConfig = getDeferredConfig(); - const partialConfig = buyersToAuctionConfigs([[bidRequest, igb]])[0][1]; - if (deferredConfig.components.hasOwnProperty(configId)) { - const {auctionConfig, deferrals} = deferredConfig.components[configId]; - if (!auctionConfig.interestGroupBuyers.includes(igb.origin)) { - const immediate = {}; - Object.entries(partialConfig).forEach(([key, value]) => { - if (deferrals.hasOwnProperty(key)) { - mergeDeep(deferrals[key], {default: value}); - } else { - immediate[key] = value; - } - }) - mergeDeep(auctionConfig, immediate); - } else { - logWarn(`Received the same PAAPI buyer multiple times for the same PAAPI auction. Consider setting paapi.componentSeller.separateAuctions: true`, igb) - } - } else { - const [deferrals, promises] = makeDeferrals(partialConfig); - const auctionConfig = { - ...partialConfig, - ...getStaticSignals(bidRequest), - ...promises, - } - deferredConfig.components[configId] = {auctionConfig, deferrals}; - deferredConfig.auctionConfig.componentAuctions.push(auctionConfig); - } - } - } - }) - } - return next.call(this, spec, bids, bidderRequest, ...args); -} - -export class AsyncPAAPIParam { - constructor(resolve) { - this.resolve = resolve; - } -} - -export function buildPAAPIParams(next, spec, bids, bidderRequest, ...args) { - if (bidderRequest.paapi?.enabled && spec.paapiParameters) { - const params = callAdapterApi(spec, 'paapiParameters', bids, bidderRequest); - return PbPromise.all( - Object.entries(params ?? {}).map(([key, value]) => - value instanceof AsyncPAAPIParam - ? value.resolve().then(result => [key, result]) - : Promise.resolve([key, value])) - ).then(resolved => { - bidderRequest.paapi.params = Object.fromEntries(resolved); - }).catch(err => { - logError(`Could not resolve PAAPI parameters`, err); - }).then(() => { - next.call(this, spec, bids, bidderRequest, ...args); - }) - } else { - next.call(this, spec, bids, bidderRequest, ...args); - } -} - -export function onAuctionInit({auctionId}) { - if (moduleConfig.parallel) { - auctionManager.index.getAuction({auctionId}).requestsDone.then(() => { - if (Object.keys(deferredConfigsForAuction(auctionId)).length > 0) { - submodules.forEach(submod => submod.onAuctionConfig?.(auctionId, configsForAuction(auctionId))); - } - }) - } -} - -export function setImpExtAe(imp, bidRequest, context) { - if (!context.bidderRequest.paapi?.enabled) { - delete imp.ext?.ae; - delete imp.ext?.igs; - } -} - -registerOrtbProcessor({type: IMP, name: 'impExtAe', fn: setImpExtAe}); - -export function parseExtIgi(response, ortbResponse, context) { - paapiResponseParser( - (ortbResponse.ext?.igi || []).flatMap(igi => { - return (igi?.igs || []).map(igs => { - if (igs.impid !== igi.impid && igs.impid != null && igi.impid != null) { - logWarn(MODULE, 'ORTB response ext.igi.igs.impid conflicts with parent\'s impid', igi); - } - return { - config: igs.config, - impid: igs.impid ?? igi.impid - } - }).concat((igi?.igb || []).map(igb => ({ - igb, - impid: igi.impid - }))) - }), - response, - context - ) -} - -function paapiResponseParser(configs, response, context) { - configs.forEach((config) => { - const impCtx = context.impContext[config.impid]; - if (!impCtx?.imp?.ext?.ae) { - logWarn(MODULE, 'Received auction configuration for an impression that was not in the request or did not ask for it', config, impCtx?.imp); - } else { - impCtx.paapiConfigs = impCtx.paapiConfigs || []; - impCtx.paapiConfigs.push(config); - } - }); -} - -// to make it easier to share code between the PBS adapter and adapters whose backend is PBS, break up -// fledge response processing in two steps: first aggregate all the auction configs by their imp... - -export function parseExtPrebidFledge(response, ortbResponse, context) { - paapiResponseParser( - (ortbResponse.ext?.prebid?.fledge?.auctionconfigs || []), - response, - context - ) -} - -registerOrtbProcessor({type: RESPONSE, name: 'extPrebidFledge', fn: parseExtPrebidFledge, dialects: [PBS]}); -registerOrtbProcessor({type: RESPONSE, name: 'extIgiIgs', fn: parseExtIgi}); - -// ...then, make them available in the adapter's response. This is the client side version, for which the -// interpretResponse api is {fledgeAuctionConfigs: [{bidId, config}]} - -export function setResponsePaapiConfigs(response, ortbResponse, context) { - const configs = Object.values(context.impContext) - .flatMap((impCtx) => (impCtx.paapiConfigs || []).map(cfg => ({ - bidId: impCtx.bidRequest.bidId, - ...cfg - }))); - if (configs.length > 0) { - response.paapi = configs; - } -} - -registerOrtbProcessor({ - type: RESPONSE, - name: 'paapiConfigs', - priority: -1, - fn: setResponsePaapiConfigs, -}); diff --git a/modules/paapiForGpt.js b/modules/paapiForGpt.js deleted file mode 100644 index 363c83ada03..00000000000 --- a/modules/paapiForGpt.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * GPT-specific slot configuration logic for PAAPI. - */ -import {getHook, submodule} from '../src/hook.js'; -import {deepAccess, logInfo, logWarn, sizeTupleToSizeString} from '../src/utils.js'; -import {config} from '../src/config.js'; -import {getGlobal} from '../src/prebidGlobal.js'; - -import {keyCompare} from '../src/utils/reducers.js'; -import {getGPTSlotsForAdUnits, targeting} from '../src/targeting.js'; - -const MODULE = 'paapiForGpt'; - -let getPAAPIConfig; - -config.getConfig('paapi', (cfg) => { - if (deepAccess(cfg, 'paapi.gpt.configWithTargeting', true)) { - logInfo(MODULE, 'enabling PAAPI configuration with setTargetingForGPTAsync') - targeting.setTargetingForGPT.before(setTargetingHook); - } else { - targeting.setTargetingForGPT.getHooks({hook: setTargetingHook}).remove(); - } -}); - -export function setTargetingHookFactory(setPaapiConfig = getGlobal().setPAAPIConfigForGPT) { - return function(next, adUnit, customSlotMatching) { - const adUnitCodes = Array.isArray(adUnit) ? adUnit : [adUnit] - adUnitCodes - .map(adUnitCode => adUnitCode == null ? undefined : {adUnitCode}) - .forEach(filters => setPaapiConfig(filters, customSlotMatching)) - next(adUnit, customSlotMatching); - } -} - -export function slotConfigurator() { - const PREVIOUSLY_SET = {}; - return function setComponentAuction(adUnitCode, gptSlots, auctionConfigs, reset = true) { - if (gptSlots.length > 0) { - let previous = PREVIOUSLY_SET[adUnitCode] ?? {}; - let configsBySeller = Object.fromEntries(auctionConfigs.map(cfg => [cfg.seller, cfg])); - const sellers = Object.keys(configsBySeller); - if (reset) { - configsBySeller = Object.assign(previous, configsBySeller); - previous = Object.fromEntries(sellers.map(seller => [seller, null])); - } else { - sellers.forEach(seller => { - previous[seller] = null; - }); - } - Object.keys(previous).length ? PREVIOUSLY_SET[adUnitCode] = previous : delete PREVIOUSLY_SET[adUnitCode]; - const componentAuction = Object.entries(configsBySeller) - .map(([configKey, auctionConfig]) => ({configKey, auctionConfig})); - if (componentAuction.length > 0) { - gptSlots.forEach(gptSlot => { - gptSlot.setConfig({componentAuction}); - logInfo(MODULE, `register component auction configs for: ${adUnitCode}: ${gptSlot.getAdUnitPath()}`, auctionConfigs); - // reference https://developers.google.com/publisher-tag/reference#googletag.config.ComponentAuctionConfig - }); - } - } else if (auctionConfigs.length > 0) { - logWarn(MODULE, `unable to register component auction config for ${adUnitCode}`, auctionConfigs); - } - }; -} - -const setComponentAuction = slotConfigurator(); - -export const getPAAPISizeHook = (() => { - /* - https://github.com/google/ads-privacy/tree/master/proposals/fledge-multiple-seller-testing#faq - https://support.google.com/admanager/answer/1100453?hl=en - - Ignore any placeholder sizes, where placeholder is defined as a square creative with a side of <= 5 pixels - Look if there are any sizes that are part of the set of supported ad sizes defined here. If there are, choose the largest supported size by area (width * height) - For clarity, the set of supported ad sizes includes all of the ad sizes listed under “Top-performing ad sizes”, “Other supported ad sizes”, and “Regional ad sizes”. - If not, choose the largest remaining size (i.e. that isn’t in the list of supported ad sizes) by area (width * height) - */ - const SUPPORTED_SIZES = [ - [728, 90], - [336, 280], - [300, 250], - [300, 50], - [160, 600], - [1024, 768], - [970, 250], - [970, 90], - [768, 1024], - [480, 320], - [468, 60], - [320, 480], - [320, 100], - [320, 50], - [300, 600], - [300, 100], - [250, 250], - [234, 60], - [200, 200], - [180, 150], - [125, 125], - [120, 600], - [120, 240], - [120, 60], - [88, 31], - [980, 120], - [980, 90], - [950, 90], - [930, 180], - [750, 300], - [750, 200], - [750, 100], - [580, 400], - [250, 360], - [240, 400], - ].sort(keyCompare(([w, h]) => -(w * h))) - .map(size => [size, sizeTupleToSizeString(size)]); - - return function(next, sizes) { - if (sizes?.length) { - const sizeStrings = new Set(sizes.map(sizeTupleToSizeString)); - const preferredSize = SUPPORTED_SIZES.find(([_, sizeStr]) => sizeStrings.has(sizeStr)); - if (preferredSize) { - next.bail(preferredSize[0]); - return; - } - } - next(sizes); - } -})(); - -export function setPAAPIConfigFactory( - getConfig = (filters) => getPAAPIConfig(filters, true), - setGptConfig = setComponentAuction, - getSlots = getGPTSlotsForAdUnits) { - /** - * Configure GPT slots with PAAPI auction configs. - * `filters` are the same filters accepted by `pbjs.getPAAPIConfig`; - */ - return function(filters = {}, customSlotMatching) { - let some = false; - const cfg = getConfig(filters) || {}; - const auToSlots = getSlots(Object.keys(cfg), customSlotMatching); - - Object.entries(cfg).forEach(([au, config]) => { - if (config != null) { - some = true; - } - setGptConfig(au, auToSlots[au], config?.componentAuctions || [], true); - }) - if (!some) { - logInfo(`${MODULE}: No component auctions available to set`); - } - } -} -/** - * Configure GPT slots with PAAPI component auctions. Accepts the same filter arguments as `pbjs.getPAAPIConfig`. - */ -getGlobal().setPAAPIConfigForGPT = setPAAPIConfigFactory(); -const setTargetingHook = setTargetingHookFactory(); - -submodule('paapi', { - name: 'gpt', - init(params) { - getPAAPIConfig = params.getPAAPIConfig; - getHook('getPAAPISize').before(getPAAPISizeHook); - } -}); diff --git a/modules/paapiForGpt.md b/modules/paapiForGpt.md deleted file mode 100644 index 8565987eb5b..00000000000 --- a/modules/paapiForGpt.md +++ /dev/null @@ -1,123 +0,0 @@ -# Overview -This module allows Prebid.js to support PAAPI by integrating it with GPT's [experimental PAAPI -support](https://github.com/google/ads-privacy/tree/master/proposals/fledge-multiple-seller-testing). - -To learn more about PAAPI in general, go [here](https://github.com/WICG/turtledove/blob/main/PAAPI.md). - -This document covers the steps necessary for publishers to enable PAAPI on their inventory. It also describes -the changes Bid Adapters need to implement in order to support PAAPI. - -## Publisher Integration -Publishers wishing to enable PAAPI support must do two things. First, they must compile Prebid.js with support for this module. -This is accomplished by adding the `paapiForGpt` module to the list of modules they are already using: - -``` -gulp build --modules=paapiForGpt,... -``` - -Second, they must enable PAAPI in their Prebid.js configuration. -This is done through module level configuration, but to provide a high degree of flexiblity for testing, PAAPI settings also exist the slot level. - -### Module Configuration -This module exposes the following settings: - -|Name |Type |Description |Notes | -| :------------ | :------------ | :------------ |:------------ | -|enabled | Boolean |Enable/disable the module |Defaults to `false` | -|bidders | Array[String] |Optional list of bidders |Defaults to all bidders | -|defaultForSlots | Number |Default value for `imp.ext.ae` in requests for specified bidders |Should be 1 | - -As noted above, PAAPI support is disabled by default. To enable it, set the `enabled` value to `true` for this module and configure `defaultForSlots` to be `1` (meaning _Client-side auction_). -using the `setConfig` method of Prebid.js. Optionally, a list of bidders to apply these settings to may be provided: - -```js -pbjs.que.push(function() { - pbjs.setConfig({ - paapi: { - enabled: true, - bidders: ['openx', 'rtbhouse'], - defaultForSlots: 1 - } - }); -}); -``` - -### AdUnit Configuration -All adunits can be opted-in to PAAPI in the global config via the `defaultForSlots` parameter. -If needed, adunits can be configured individually by setting an attribute of the `ortb2Imp` object for that -adunit. This attribute will take precedence over `defaultForSlots` setting. - -|Name |Type |Description |Notes | -| :------------ | :------------ | :------------ |:------------ | -| ortb2Imp.ext.ae | Integer | Auction Environment: 1 indicates PAAPI eligible, 0 indicates it is not | Absence indicates this is not PAAPI eligible | - -The `ae` field stands for Auction Environment and was chosen to be consistent with the field that GAM passes to bidders -in their Open Bidding and Exchange Bidding APIs. More details on that can be found -[here](https://github.com/google/ads-privacy/tree/master/proposals/fledge-rtb#bid-request-changes-indicating-interest-group-auction-support) -In practice, this looks as follows: - -```js -pbjs.addAdUnits({ - code: "my-adunit-div", - // other config here - ortb2Imp: { - ext: { - ae: 1 - } - } -}); -``` - -## Bid Adapter Integration -Chrome has enabled a two-tier auction in PAAPI. This allows multiple sellers (frequently SSPs) to act on behalf of the publisher with -a single entity serving as the final decision maker. In their [current approach](https://github.com/google/ads-privacy/tree/master/proposals/fledge-multiple-seller-testing), -GPT has opted to run the final auction layer while allowing other SSPs/sellers to participate as -[Component Auctions](https://github.com/WICG/turtledove/blob/main/PAAPI.md#21-initiating-an-on-device-auction) which feed their -bids to the final layer. To learn more about Component Auctions, go [here](https://github.com/WICG/turtledove/blob/main/PAAPI.md#24-scoring-bids-in-component-auctions). - -The PAAPI auction, including Component Auctions, are configured via an `AuctionConfig` object that defines the parameters of the auction for a given -seller. This module enables PAAPI support by allowing bid adaptors to return `AuctionConfig` objects in addition to bids. If a bid adaptor returns an -`AuctionConfig` object, Prebid.js will register it with the appropriate GPT ad slot so the bidder can participate as a Component Auction in the overall -PAAPI auction for that slot. More details on the GPT API can be found [here](https://developers.google.com/publisher-tag/reference#googletag.config.componentauctionconfig). - -Modifying a bid adapter to support PAAPI is a straightforward process and consists of the following steps: -1. Detecting when a bid request is PAAPI eligible -2. Responding with AuctionConfig - -PAAPI eligibility is made available to bid adapters through the `bidderRequest.paapi.enabled` field. -The [`bidderRequest`](https://docs.prebid.org/dev-docs/bidder-adaptor.html#bidderrequest-parameters) object is passed to -the [`buildRequests`](https://docs.prebid.org/dev-docs/bidder-adaptor.html#building-the-request) method of an adapter. Bid adapters -who wish to participate should read this flag and pass it to their server. PAAPI eligibility depends on a number of parameters: - -1. Chrome enablement -2. Publisher participatipon in the [Origin Trial](https://developer.chrome.com/docs/privacy-sandbox/unified-origin-trial/#configure) -3. Publisher Prebid.js configuration (detailed above) - -When a bid request is PAAPI enabled, a bid adapter can return a tuple consisting of bids and AuctionConfig objects rather than just a list of bids: - -```js -function interpretResponse(resp, req) { - // Load the bids from the response - this is adapter specific - const bids = parseBids(resp); - - // Load the auctionConfigs from the response - also adapter specific - const auctionConfigs = parseAuctionConfigs(resp); - - if (auctionConfigs) { - // Return a tuple of bids and auctionConfigs. It is possible that bids could be null. - return {bids, auctionConfigs}; - } else { - return bids; - } -} -``` - -An AuctionConfig must be associated with an adunit and auction, and this is accomplished using the value in the `bidId` field from the objects in the -`validBidRequests` array passed to the `buildRequests` function - see [here](https://docs.prebid.org/dev-docs/bidder-adaptor.html#ad-unit-params-in-the-validbidrequests-array) -for more details. This means that the AuctionConfig objects returned from `interpretResponse` must contain a `bidId` field whose value corresponds to -the request it should be associated with. This may raise the question: why isn't the AuctionConfig object returned as part of the bid? The -answer is that it's possible to participate in the PAAPI auction without returning a contextual bid. - -An example of this can be seen in the OpenX OpenRTB bid adapter [here](https://github.com/prebid/Prebid.js/blob/master/modules/openxOrtbBidAdapter.js#L327). - -Other than the addition of the `bidId` field, the AuctionConfig object should adhere to the requirements set forth in PAAPI. The details of creating an AuctionConfig object are beyond the scope of this document. diff --git a/modules/panxoBidAdapter.js b/modules/panxoBidAdapter.js index 6f9eb80ae84..1a898b64887 100644 --- a/modules/panxoBidAdapter.js +++ b/modules/panxoBidAdapter.js @@ -8,6 +8,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { deepAccess, logWarn, isFn, isPlainObject } from '../src/utils.js'; import { getStorageManager } from '../src/storageManager.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'panxo'; const ENDPOINT_URL = 'https://panxo-sys.com/openrtb/2.5/bid'; @@ -112,7 +113,7 @@ function buildDevice() { ua: navigator.userAgent, language: navigator.language, js: 1, - dnt: navigator.doNotTrack === '1' ? 1 : 0 + dnt: getDNT() ? 1 : 0 }; if (typeof screen !== 'undefined') { diff --git a/modules/prebidServerBidAdapter/index.ts b/modules/prebidServerBidAdapter/index.ts index 71abec10cee..e2dcaf8bd28 100644 --- a/modules/prebidServerBidAdapter/index.ts +++ b/modules/prebidServerBidAdapter/index.ts @@ -21,7 +21,7 @@ import { import {DEBUG_MODE, EVENTS, REJECTION_REASON, S2S} from '../../src/constants.js'; import adapterManager, {s2sActivityParams} from '../../src/adapterManager.js'; import {config} from '../../src/config.js'; -import {addPaapiConfig, isValid} from '../../src/adapters/bidderFactory.js'; +import {isValid} from '../../src/adapters/bidderFactory.js'; import * as events from '../../src/events.js'; import {ajax} from '../../src/ajax.js'; import {hook} from '../../src/hook.js'; @@ -459,7 +459,6 @@ export type PbsAnalytics = SeatNonBid & { declare module '../../src/events' { interface Events { - [EVENTS.SEAT_NON_BID]: [SeatNonBid]; [EVENTS.PBS_ANALYTICS]: [PbsAnalytics]; [EVENTS.BEFORE_PBS_HTTP]: [PbsRequestData]; } @@ -497,15 +496,6 @@ export function PrebidServer() { bidRequests.forEach(bidderRequest => events.emit(EVENTS.BIDDER_DONE, bidderRequest)); } const { seatNonBidData, atagData } = getAnalyticsFlags(s2sBidRequest.s2sConfig, response) - if (seatNonBidData) { - events.emit(EVENTS.SEAT_NON_BID, { - seatnonbid: response.ext.seatnonbid, - auctionId: bidRequests[0].auctionId, - requestedBidders, - response, - adapterMetrics - }); - } // pbs analytics event if (seatNonBidData || atagData) { const data: PbsAnalytics = { @@ -544,11 +534,6 @@ export function PrebidServer() { addBidResponse.reject(adUnit, bid, REJECTION_REASON.INVALID); } } - }, - onFledge: (params) => { - config.runWithBidder(params.bidder, () => { - addPaapiConfig({auctionId: bidRequests[0].auctionId, ...params}, {config: params.config}); - }) } }) } @@ -577,7 +562,7 @@ type PbsRequestData = { * @param onError {function(String, {})} invoked on HTTP failure - with status message and XHR error * @param onBid {function({})} invoked once for each bid in the response - with the bid as returned by interpretResponse */ -export const processPBSRequest = hook('async', function (s2sBidRequest, bidRequests, ajax, {onResponse, onError, onBid, onFledge}) { +export const processPBSRequest = hook('async', function (s2sBidRequest, bidRequests, ajax, {onResponse, onError, onBid}) { const { gdprConsent } = getConsentData(bidRequests); const adUnits = deepClone(s2sBidRequest.ad_units); @@ -606,11 +591,8 @@ export const processPBSRequest = hook('async', function (s2sBidRequest, bidReque let result; try { result = JSON.parse(response); - const {bids, paapi} = s2sBidRequest.metrics.measureTime('interpretResponse', () => interpretPBSResponse(result, request)); + const {bids} = s2sBidRequest.metrics.measureTime('interpretResponse', () => interpretPBSResponse(result, request)); bids.forEach(onBid); - if (paapi) { - paapi.forEach(onFledge); - } } catch (error) { logError(error); } diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index ab9e18e6837..4a053849eb6 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -248,23 +248,6 @@ const PBS_CONVERTER = ortbConverter({ // override to process each request context.actualBidderRequests.forEach(req => orig(response, ortbResponse, {...context, bidderRequest: req, bidRequests: req.bids})); }, - paapiConfigs(orig, response, ortbResponse, context) { - const configs = Object.values(context.impContext) - .flatMap((impCtx) => (impCtx.paapiConfigs || []).map(cfg => { - const bidderReq = impCtx.actualBidderRequests.find(br => br.bidderCode === cfg.bidder); - const bidReq = impCtx.actualBidRequests.get(cfg.bidder); - return { - adUnitCode: impCtx.adUnit.code, - ortb2: bidderReq?.ortb2, - ortb2Imp: bidReq?.ortb2Imp, - bidder: cfg.bidder, - config: cfg.config - }; - })); - if (configs.length > 0) { - response.paapi = configs; - } - } } }, }); @@ -317,9 +300,6 @@ export function buildPBSRequest(s2sBidRequest, bidderRequests, adUnits, requeste const proxyBidderRequest = { ...Object.fromEntries(Object.entries(bidderRequests[0]).filter(([k]) => !BIDDER_SPECIFIC_REQUEST_PROPS.has(k))), - paapi: { - enabled: bidderRequests.some(br => br.paapi?.enabled) - } } return PBS_CONVERTER.toORTB({ diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index f23665670e9..e0b61880fb7 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1,6 +1,6 @@ import { logWarn, isStr, isArray, deepAccess, deepSetValue, isBoolean, isInteger, logInfo, logError, deepClone, uniques, generateUUID, isPlainObject, isFn, getWindowTop } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO, NATIVE, ADPOD } from '../src/mediaTypes.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { isViewabilityMeasurable, getViewability } from '../libraries/percentInView/percentInView.js'; @@ -142,12 +142,11 @@ const converter = ortbConverter({ if (mediaType === VIDEO) { if (!bidResponse.width) bidResponse.width = playerWidth; if (!bidResponse.height) bidResponse.height = playerHeight; - const { context, maxduration } = mediaTypes[mediaType]; + const { context } = mediaTypes[mediaType]; if (context === 'outstream' && params.outstreamAU && adUnitCode) { bidResponse.rendererCode = params.outstreamAU; bidResponse.renderer = BB_RENDERER.newRenderer(bidResponse.rendererCode, adUnitCode); } - assignDealTier(bidResponse, context, maxduration); } if (mediaType === NATIVE && bid.adm) { try { @@ -524,27 +523,6 @@ const addExtenstionParams = (req, bidderRequest) => { } } -/** - * In case of adpod video context, assign prebiddealpriority to the dealtier property of adpod-video bid, - * so that adpod module can set the hb_pb_cat_dur targetting key. - * @param {*} bid - * @param {*} context - * @param {*} maxduration - * @returns - */ -const assignDealTier = (bid, context, maxduration) => { - if (!bid?.ext?.prebiddealpriority || !FEATURES.VIDEO) return; - if (context !== ADPOD) return; - - const duration = bid?.ext?.video?.duration || maxduration; - // if (!duration) return; - bid.video = { - context: ADPOD, - durationSeconds: duration, - dealTier: bid.ext.prebiddealpriority - }; -} - const validateAllowedCategories = (acat) => { return [...new Set( acat diff --git a/modules/pwbidBidAdapter.js b/modules/pwbidBidAdapter.js index cb383fee630..854d56e4ae0 100644 --- a/modules/pwbidBidAdapter.js +++ b/modules/pwbidBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { _each, isBoolean, isNumber, isStr, deepClone, isArray, deepSetValue, inIframe, mergeDeep, deepAccess, logMessage, logInfo, logWarn, logError, isPlainObject } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { OUTSTREAM, INSTREAM } from '../src/video.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/quantcastBidAdapter.js b/modules/quantcastBidAdapter.js deleted file mode 100644 index 0ee58a927d1..00000000000 --- a/modules/quantcastBidAdapter.js +++ /dev/null @@ -1,297 +0,0 @@ -import {deepAccess, isArray, isEmpty, logError, logInfo} from '../src/utils.js'; -import {ajax} from '../src/ajax.js'; -import {config} from '../src/config.js'; -import {getStorageManager} from '../src/storageManager.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {parseDomain} from '../src/refererDetection.js'; - -/** - * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest - * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid - */ - -const BIDDER_CODE = 'quantcast'; -const DEFAULT_BID_FLOOR = 0.0000000001; - -const QUANTCAST_VENDOR_ID = '11'; -// Check other required purposes on server -const PURPOSE_DATA_COLLECT = '1'; - -export const QUANTCAST_DOMAIN = 'qcx.quantserve.com'; -export const QUANTCAST_TEST_DOMAIN = 's2s-canary.quantserve.com'; -export const QUANTCAST_NET_REVENUE = true; -export const QUANTCAST_TEST_PUBLISHER = 'test-publisher'; -export const QUANTCAST_TTL = 4; -export const QUANTCAST_PROTOCOL = 'https'; -export const QUANTCAST_PORT = '8443'; -export const QUANTCAST_FPA = '__qca'; - -export const storage = getStorageManager({bidderCode: BIDDER_CODE}); - -function makeVideoImp(bid) { - const videoInMediaType = deepAccess(bid, 'mediaTypes.video') || {}; - const videoInParams = deepAccess(bid, 'params.video') || {}; - const video = Object.assign({}, videoInParams, videoInMediaType); - - if (video.playerSize) { - video.w = video.playerSize[0]; - video.h = video.playerSize[1]; - } - const videoCopy = { - mimes: video.mimes, - minduration: video.minduration, - maxduration: video.maxduration, - protocols: video.protocols, - startdelay: video.startdelay, - linearity: video.linearity, - battr: video.battr, - maxbitrate: video.maxbitrate, - playbackmethod: video.playbackmethod, - delivery: video.delivery, - api: video.api, - w: video.w, - h: video.h - } - - return { - video: videoCopy, - placementCode: bid.placementCode, - bidFloor: DEFAULT_BID_FLOOR - }; -} - -function makeBannerImp(bid) { - const sizes = bid.sizes || bid.mediaTypes.banner.sizes; - - return { - banner: { - battr: bid.params.battr, - sizes: sizes.map(size => { - return { - width: size[0], - height: size[1] - }; - }) - }, - placementCode: bid.placementCode, - bidFloor: DEFAULT_BID_FLOOR - }; -} - -function checkTCF(tcData) { - const restrictions = tcData.publisher ? tcData.publisher.restrictions : {}; - const qcRestriction = restrictions && restrictions[PURPOSE_DATA_COLLECT] - ? restrictions[PURPOSE_DATA_COLLECT][QUANTCAST_VENDOR_ID] - : null; - - if (qcRestriction === 0 || qcRestriction === 2) { - // Not allowed by publisher, or requires legitimate interest - return false; - } - - const vendorConsent = tcData.vendor && tcData.vendor.consents && tcData.vendor.consents[QUANTCAST_VENDOR_ID]; - const purposeConsent = tcData.purpose && tcData.purpose.consents && tcData.purpose.consents[PURPOSE_DATA_COLLECT]; - - return !!(vendorConsent && purposeConsent); -} - -function getQuantcastFPA() { - const fpa = storage.getCookie(QUANTCAST_FPA) - return fpa || '' -} - -let hasUserSynced = false; - -/** - * The documentation for Prebid.js Adapter 1.0 can be found at link below, - * http://prebid.org/dev-docs/bidder-adapter-1.html - */ -export const spec = { - code: BIDDER_CODE, - gvlid: QUANTCAST_VENDOR_ID, - supportedMediaTypes: ['banner', 'video'], - - /** - * Verify the `AdUnits.bids` response with `true` for valid request and `false` - * for invalid request. - * - * @param {object} bid - * @return boolean `true` is this is a valid bid, and `false` otherwise - */ - isBidRequestValid(bid) { - return !!bid.params.publisherId; - }, - - /** - * Make a server request when the page asks Prebid.js for bids from a list of - * `BidRequests`. - * - * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be send to Quantcast server - * @param bidderRequest - * @return ServerRequest information describing the request to the server. - */ - buildRequests(bidRequests, bidderRequest) { - const bids = bidRequests || []; - const gdprConsent = deepAccess(bidderRequest, 'gdprConsent') || {}; - const uspConsent = deepAccess(bidderRequest, 'uspConsent'); - const referrer = deepAccess(bidderRequest, 'refererInfo.ref'); - const page = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href'); - const domain = parseDomain(page, {noLeadingWww: true}); - - // Check for GDPR consent for purpose 1, and drop request if consent has not been given - // Remaining consent checks are performed server-side. - if (gdprConsent.gdprApplies) { - if (gdprConsent.vendorData) { - if (!checkTCF(gdprConsent.vendorData)) { - logInfo(`${BIDDER_CODE}: No purpose 1 consent for TCF v2`); - return; - } - } - } - - const bidRequestsList = []; - - bids.forEach(bid => { - let imp; - if (bid.mediaTypes) { - if (bid.mediaTypes.video && bid.mediaTypes.video.context === 'instream') { - imp = makeVideoImp(bid); - } else if (bid.mediaTypes.banner) { - imp = makeBannerImp(bid); - } else { - // Unsupported mediaType - logInfo(`${BIDDER_CODE}: No supported mediaTypes found in ${JSON.stringify(bid.mediaTypes)}`); - return; - } - } else { - // Parse as banner by default - imp = makeBannerImp(bid); - } - - // Request Data Format can be found at https://wiki.corp.qc/display/adinf/QCX - const requestData = { - publisherId: bid.params.publisherId, - requestId: bid.bidId, - imp: [imp], - site: { - page, - referrer, - domain - }, - bidId: bid.bidId, - gdprSignal: gdprConsent.gdprApplies ? 1 : 0, - gdprConsent: gdprConsent.consentString, - uspSignal: uspConsent ? 1 : 0, - uspConsent, - coppa: config.getConfig('coppa') === true ? 1 : 0, - prebidJsVersion: '$prebid.version$', - fpa: getQuantcastFPA() - }; - - const data = JSON.stringify(requestData); - const qcDomain = bid.params.publisherId === QUANTCAST_TEST_PUBLISHER - ? QUANTCAST_TEST_DOMAIN - : QUANTCAST_DOMAIN; - const url = `${QUANTCAST_PROTOCOL}://${qcDomain}:${QUANTCAST_PORT}/qchb`; - - bidRequestsList.push({ - data, - method: 'POST', - url - }); - }); - - return bidRequestsList; - }, - - /** - * Function get called when the browser has received the response from Quantcast server. - * The function parse the response and create a `bidResponse` object containing one/more bids. - * Returns an empty array if no valid bids - * - * Response Data Format can be found at https://wiki.corp.qc/display/adinf/QCX - * - * @param {*} serverResponse A successful response from Quantcast server. - * @return {Bid[]} An array of bids which were nested inside the server. - * - */ - interpretResponse(serverResponse) { - if (serverResponse === undefined) { - logError('Server Response is undefined'); - return []; - } - - const response = serverResponse['body']; - - if (response === undefined || !response.hasOwnProperty('bids')) { - logError('Sub-optimal JSON received from Quantcast server'); - return []; - } - - if (isEmpty(response.bids)) { - // Shortcut response handling if no bids are present - return []; - } - - const bidResponsesList = response.bids.map(bid => { - const { ad, cpm, width, height, creativeId, currency, videoUrl, dealId, meta } = bid; - - const result = { - requestId: response.requestId, - cpm, - width, - height, - ad, - ttl: QUANTCAST_TTL, - creativeId, - netRevenue: QUANTCAST_NET_REVENUE, - currency - }; - - if (videoUrl !== undefined && videoUrl) { - result['vastUrl'] = videoUrl; - result['mediaType'] = 'video'; - } - - if (dealId !== undefined && dealId) { - result['dealId'] = dealId; - } - - if (meta !== undefined && meta.advertiserDomains && isArray(meta.advertiserDomains)) { - result.meta = {}; - result.meta.advertiserDomains = meta.advertiserDomains; - } - - return result; - }); - - return bidResponsesList; - }, - onTimeout(timeoutData) { - const url = `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb_notify?type=timeout`; - ajax(url, null, null); - }, - getUserSyncs(syncOptions, serverResponses) { - const syncs = [] - if (!hasUserSynced && syncOptions.pixelEnabled) { - const responseWithUrl = ((serverResponses) || []).find(serverResponse => - deepAccess(serverResponse.body, 'userSync.url') - ); - - if (responseWithUrl) { - const url = deepAccess(responseWithUrl.body, 'userSync.url') - syncs.push({ - type: 'image', - url: url - }); - } - hasUserSynced = true; - } - return syncs; - }, - resetUserSync() { - hasUserSynced = false; - } -}; - -registerBidder(spec); diff --git a/modules/quantcastBidAdapter.md b/modules/quantcastBidAdapter.md deleted file mode 100644 index edbbc538b65..00000000000 --- a/modules/quantcastBidAdapter.md +++ /dev/null @@ -1,74 +0,0 @@ -# Overview - -``` -Module Name: Quantcast Bidder Adapter -Module Type: Bidder Adapter -Maintainer: inventoryteam@quantcast.com -``` - -# Description - -Module that connects to Quantcast demand sources to fetch bids. - -# Test Parameters - -## Sample Banner Ad Unit -```js -const adUnits = [{ - code: 'banner', - sizes: [ - [300, 250] - ], - bids: [ - { - bidder: 'quantcast', - params: { - publisherId: 'test-publisher', // REQUIRED - Publisher ID provided by Quantcast - battr: [1, 2] // OPTIONAL - Array of blocked creative attributes as per OpenRTB Spec List 5.3 - } - } - ], - userSync: { - url: 'https://quantcast.com/pixelUrl' - } -}]; -``` - -## Sample Video Ad Unit -```js -var adUnits = [{ - code: 'video', - mediaTypes: { - video: { - context: 'instream', // required - playerSize: [600, 300] // required - } - }, - bids: [ - { - bidder: 'quantcast', - params: { - publisherId: 'test-publisher', // REQUIRED - Publisher ID provided by Quantcast - // Video object as specified in OpenRTB 2.5 - video: { - mimes: ['video/mp4'], // required - minduration: 3, // optional - maxduration: 5, // optional - protocols: [3], // optional - startdelay: 1, // optional - linearity: 1, // optinal - battr: [1, 2], // optional - maxbitrate: 10, // optional - playbackmethod: [1], // optional - delivery: [1], // optional - placement: 1, // optional - api: [2, 3] // optional - } - } - } - ], - userSync: { - url: 'https://quantcast.com/pixelUrl' - } -}]; -``` diff --git a/modules/quantcastIdSystem.js b/modules/quantcastIdSystem.js deleted file mode 100644 index aeccceb0d10..00000000000 --- a/modules/quantcastIdSystem.js +++ /dev/null @@ -1,230 +0,0 @@ -/** - * This module adds QuantcastID to the User ID module - * The {@link module:modules/userId} module is required - * @module modules/quantcastIdSystem - * @requires module:modules/userId - */ - -import {submodule} from '../src/hook.js' -import {getStorageManager} from '../src/storageManager.js'; -import { triggerPixel, logInfo } from '../src/utils.js'; -import { uspDataHandler, coppaDataHandler, gdprDataHandler } from '../src/adapterManager.js'; -import {MODULE_TYPE_UID} from '../src/activities/modules.js'; - -/** - * @typedef {import('../modules/userId/index.js').Submodule} Submodule - */ - -const QUANTCAST_FPA = '__qca'; -const DEFAULT_COOKIE_EXP_DAYS = 392; // (13 months - 2 days) -const DAY_MS = 86400000; -const PREBID_PCODE = 'p-KceJUEvXN48CE'; -const QSERVE_URL = 'https://pixel.quantserve.com/pixel'; -const QUANTCAST_VENDOR_ID = '11'; -const PURPOSE_DATA_COLLECT = '1'; -const PURPOSE_PRODUCT_IMPROVEMENT = '10'; -const QC_TCF_REQUIRED_PURPOSES = [PURPOSE_DATA_COLLECT, PURPOSE_PRODUCT_IMPROVEMENT]; -const QC_TCF_CONSENT_FIRST_PURPOSES = [PURPOSE_DATA_COLLECT]; -const QC_TCF_CONSENT_ONLY_PUPROSES = [PURPOSE_DATA_COLLECT]; -const GDPR_PRIVACY_STRING = gdprDataHandler.getConsentData(); -const US_PRIVACY_STRING = uspDataHandler.getConsentData(); -const MODULE_NAME = 'quantcastId'; - -export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME}); - -export function firePixel(clientId, cookieExpDays = DEFAULT_COOKIE_EXP_DAYS) { - // check for presence of Quantcast Measure tag _qevent obj and publisher provided clientID - if (!window._qevents && clientId) { - var fpa = storage.getCookie(QUANTCAST_FPA); - var fpan = '0'; - var domain = quantcastIdSubmodule.findRootDomain(); - var now = new Date(); - var usPrivacyParamString = ''; - var firstPartyParamStrings; - var gdprParamStrings; - - if (!fpa) { - var et = now.getTime(); - var expires = new Date(et + (cookieExpDays * DAY_MS)).toGMTString(); - var rand = Math.round(Math.random() * 2147483647); - fpa = `B0-${rand}-${et}`; - fpan = '1'; - storage.setCookie(QUANTCAST_FPA, fpa, expires, '/', domain, null); - } - - firstPartyParamStrings = `&fpan=${fpan}&fpa=${fpa}`; - gdprParamStrings = '&gdpr=0'; - if (GDPR_PRIVACY_STRING && typeof GDPR_PRIVACY_STRING.gdprApplies === 'boolean' && GDPR_PRIVACY_STRING.gdprApplies) { - gdprParamStrings = `gdpr=1&gdpr_consent=${GDPR_PRIVACY_STRING.consentString}`; - } - if (US_PRIVACY_STRING && typeof US_PRIVACY_STRING === 'string') { - usPrivacyParamString = `&us_privacy=${US_PRIVACY_STRING}`; - } - - const url = QSERVE_URL + - '?d=' + domain + - '&client_id=' + clientId + - '&a=' + PREBID_PCODE + - usPrivacyParamString + - gdprParamStrings + - firstPartyParamStrings; - - triggerPixel(url); - } -}; - -export function hasGDPRConsent(gdprConsent) { - // Check for GDPR consent for purpose 1 and 10, and drop request if consent has not been given - // Remaining consent checks are performed server-side. - if (gdprConsent && typeof gdprConsent.gdprApplies === 'boolean' && gdprConsent.gdprApplies) { - if (!gdprConsent.vendorData) { - return false; - } - return checkTCFv2(gdprConsent.vendorData); - } - return true; -} - -export function checkTCFv2(vendorData, requiredPurposes = QC_TCF_REQUIRED_PURPOSES) { - var gdprApplies = vendorData.gdprApplies; - var purposes = vendorData.purpose; - var vendors = vendorData.vendor; - var qcConsent = vendors && vendors.consents && vendors.consents[QUANTCAST_VENDOR_ID]; - var qcInterest = vendors && vendors.legitimateInterests && vendors.legitimateInterests[QUANTCAST_VENDOR_ID]; - var restrictions = vendorData.publisher ? vendorData.publisher.restrictions : {}; - - if (!gdprApplies) { - return true; - } - - return requiredPurposes.map(function(purpose) { - var purposeConsent = purposes.consents ? purposes.consents[purpose] : false; - var purposeInterest = purposes.legitimateInterests ? purposes.legitimateInterests[purpose] : false; - - var qcRestriction = restrictions && restrictions[purpose] - ? restrictions[purpose][QUANTCAST_VENDOR_ID] - : null; - - if (qcRestriction === 0) { - return false; - } - - // Seek consent or legitimate interest based on our default legal - // basis for the purpose, falling back to the other if possible. - if ( - // we have positive vendor consent - qcConsent && - // there is positive purpose consent - purposeConsent && - // publisher does not require legitimate interest - qcRestriction !== 2 && - // purpose is a consent-first purpose or publisher has explicitly restricted to consent - (QC_TCF_CONSENT_FIRST_PURPOSES.indexOf(purpose) !== -1 || qcRestriction === 1) - ) { - return true; - } else if ( - // publisher does not require consent - qcRestriction !== 1 && - // we have legitimate interest for vendor - qcInterest && - // there is legitimate interest for purpose - purposeInterest && - // purpose's legal basis does not require consent - QC_TCF_CONSENT_ONLY_PUPROSES.indexOf(purpose) === -1 && - // purpose is a legitimate-interest-first purpose or publisher has explicitly restricted to legitimate interest - (QC_TCF_CONSENT_FIRST_PURPOSES.indexOf(purpose) === -1 || qcRestriction === 2) - ) { - return true; - } - - return false; - }).reduce(function(a, b) { - return a && b; - }, true); -} - -/** - * tests if us_privacy consent string is present, us_privacy applies, and notice_given / do-not-sell is set to yes - * @returns {boolean} - */ -export function hasCCPAConsent(usPrivacyConsent) { - if ( - usPrivacyConsent && - typeof usPrivacyConsent === 'string' && - usPrivacyConsent.length === 4 && - usPrivacyConsent.charAt(1) === 'Y' && - usPrivacyConsent.charAt(2) === 'Y' - ) { - return false - } - return true; -} - -/** @type {Submodule} */ -export const quantcastIdSubmodule = { - /** - * used to link submodule with config - * @type {string} - */ - name: MODULE_NAME, - - /** - * Vendor id of Quantcast - * @type {Number} - */ - gvlid: QUANTCAST_VENDOR_ID, - - /** - * decode the stored id value for passing to bid requests - * @function - * @returns {{quantcastId: string} | undefined} - */ - decode(value) { - return value; - }, - - /** - * read Quantcast first party cookie and pass it along in quantcastId - * @function - * @returns {{id: {quantcastId: string} | undefined}}} - */ - getId(config) { - // Consent signals are currently checked on the server side. - const fpa = storage.getCookie(QUANTCAST_FPA); - - const coppa = coppaDataHandler.getCoppa(); - - if (coppa || !hasCCPAConsent(US_PRIVACY_STRING) || !hasGDPRConsent(GDPR_PRIVACY_STRING)) { - var expired = new Date(0).toUTCString(); - var domain = quantcastIdSubmodule.findRootDomain(); - logInfo('QuantcastId: Necessary consent not present for Id, exiting QuantcastId'); - storage.setCookie(QUANTCAST_FPA, '', expired, '/', domain, null); - return undefined; - } - - const configParams = (config && config.params) || {}; - const storageParams = (config && config.storage) || {}; - - var clientId = configParams.clientId || ''; - var cookieExpDays = storageParams.expires || DEFAULT_COOKIE_EXP_DAYS; - - // Callbacks on Event Listeners won't trigger if the event is already complete so this check is required - if (document.readyState === 'complete') { - firePixel(clientId, cookieExpDays); - } else { - window.addEventListener('load', function () { - firePixel(clientId, cookieExpDays); - }); - } - - return { id: fpa ? { quantcastId: fpa } : undefined }; - }, - eids: { - 'quantcastId': { - source: 'quantcast.com', - atype: 1 - }, - } -}; - -submodule('userId', quantcastIdSubmodule); diff --git a/modules/quantcastIdSystem.md b/modules/quantcastIdSystem.md deleted file mode 100644 index 7e90764432b..00000000000 --- a/modules/quantcastIdSystem.md +++ /dev/null @@ -1,46 +0,0 @@ -#### Overview - -``` -Module Name: Quantcast Id System -Module Type: Id System -Maintainer: asig@quantcast.com -``` - -#### Description - - The Prebid Quantcast ID module stores a Quantcast ID in a first party cookie. The ID is then made available in the bid request. The ID from the cookie added in the bidstream allows Quantcast to more accurately bid on publisher inventories without third party cookies, which can result in better monetization across publisher sites from Quantcast. And, it’s free to use! For easier integration, you can work with one of our SSP partners, like PubMatic, who can facilitate the legal process as well as the software integration for you. - - Add it to your Prebid.js package with: - - `gulp build --modules=userId,quantcastIdSystem` - - Quantcast’s privacy policies for the services rendered can be found at - https://www.quantcast.com/privacy/ - - Publishers deploying the module are responsible for ensuring legally required notices and choices for users. - - The Quantcast ID module will only perform any action and return an ID in situations where: - 1. the publisher has not set a ‘coppa' flag on the prebid configuration on their site (see [pbjs.setConfig.coppa](https://docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html#setConfig-coppa)) - 2. there is not a IAB us-privacy string indicating the digital property has provided user notice and the user has made a choice to opt out of sale - 3. if GDPR applies, an IAB TCF v2 string exists indicating that Quantcast does not have consent for purpose 1 (cookies, device identifiers, or other information can be stored or accessed on your device for the purposes presented to you), or an established legal basis (by default legitimate interest) for purpose 10 (your data can be used to improve existing systems and software, and to develop new products). - - #### Quantcast ID Configuration - - | Param under userSync.userIds[] | Scope | Type | Description | Example | - | --- | --- | --- | --- | --- | - | name | Required | String | `"quantcastId"` | `"quantcastId"` | - | params | Optional | Object | Details for Quantcast initialization. | | - | params.ClientID | Optional | String | Optional parameter for Quantcast prebid managed service partners. The parameter is not required for websites with Quantcast Measure tag. Reach out to Quantcast for ClientID if you are not an existing Quantcast prebid managed service partner: quantcast-idsupport@quantcast.com. | | - - - #### Quantcast ID Example - -```js - pbjs.setConfig({ - userSync: { - userIds: [{ - name: "quantcastId" - }] - } - }); -``` diff --git a/modules/rhythmoneBidAdapter.js b/modules/rhythmoneBidAdapter.js index e3d4b15aebc..173c8e0649f 100644 --- a/modules/rhythmoneBidAdapter.js +++ b/modules/rhythmoneBidAdapter.js @@ -1,9 +1,9 @@ 'use strict'; -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, parseSizesInput, isArray } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {getDNT} from '../libraries/dnt/index.js'; function RhythmOneBidAdapter() { this.code = 'rhythmone'; diff --git a/modules/ringieraxelspringerBidAdapter.js b/modules/ringieraxelspringerBidAdapter.js deleted file mode 100644 index c5b7e000f87..00000000000 --- a/modules/ringieraxelspringerBidAdapter.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Backward-compatibility shim for ringieraxelspringer bidder. - * This bidder has been renamed to 'das'. - * - * This file will be removed in Prebid 11. - * See dasBidAdapter.js for implementation. - */ -export { spec } from './dasBidAdapter.js'; // eslint-disable-line prebid/validate-imports diff --git a/modules/ringieraxelspringerBidAdapter.md b/modules/ringieraxelspringerBidAdapter.md deleted file mode 100644 index 4527d9f8c6d..00000000000 --- a/modules/ringieraxelspringerBidAdapter.md +++ /dev/null @@ -1,8 +0,0 @@ -# Overview - -The `ringieraxelspringer` bidder has been renamed to `das`. -Please use the `das` bidder code instead. - -See [dasBidAdapter.md](./dasBidAdapter.md) for documentation. - -This adapter will be removed in Prebid 11. diff --git a/modules/rtbhouseBidAdapter.md b/modules/rtbhouseBidAdapter.md index 7fcae1299b2..b8b59aa9edc 100644 --- a/modules/rtbhouseBidAdapter.md +++ b/modules/rtbhouseBidAdapter.md @@ -65,46 +65,3 @@ Please reach out to pmp@rtbhouse.com to receive your own } ]; ``` - -# Protected Audience API (FLEDGE) support -There’s an option to receive demand for Protected Audience API (FLEDGE/PAAPI) -ads using RTB House bid adapter. -Prebid’s [paapiForGpt](https://docs.prebid.org/dev-docs/modules/paapiForGpt.html) -module and Google Ad Manager is currently required. - -The following steps should be taken to setup Protected Audience for RTB House: - -1. Reach out to your RTB House representative for setup coordination. - -2. Build and enable FLEDGE module as described in -[paapiForGpt](https://docs.prebid.org/dev-docs/modules/paapiForGpt.html) -module documentation. - - a. Make sure to enable RTB House bidder to participate in FLEDGE. If there are any other bidders to be allowed for that, add them to the **bidders** array: - ```javascript - pbjs.setConfig({ - paapi: { - bidders: ["rtbhouse"], - enabled: true - } - }); - ``` - - b. If you as a publisher have your own [decisionLogicUrl](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#21-initiating-an-on-device-auction) - you may utilize it by setting up a dedicated `fledgeConfig` object: - ```javascript - pbjs.setConfig({ - paapi: { - bidders: ["rtbhouse"], - enabled: true - }, - fledgeConfig: { - seller: 'https://seller.domain', - decisionLogicUrl: 'https://seller.domain/decisionLogicFile.js', - sellerTimeout: 100 - } - }); - ``` - The `decisionLogicUrl` must be in the same domain as `seller` and has to respond with `X-Allow-FLEDGE: true` http header. - - `sellerTimeout` is optional, defaults to 50 as per spec, will be clamped to 500 if greater. diff --git a/modules/rtdModule/index.ts b/modules/rtdModule/index.ts index 1b3bff0baf3..440eae27fd9 100644 --- a/modules/rtdModule/index.ts +++ b/modules/rtdModule/index.ts @@ -53,8 +53,7 @@ const setEventsListeners = (function () { [EVENTS.AUCTION_INIT]: ['onAuctionInitEvent'], [EVENTS.AUCTION_END]: ['onAuctionEndEvent', getAdUnitTargeting], [EVENTS.BID_RESPONSE]: ['onBidResponseEvent'], - [EVENTS.BID_REQUESTED]: ['onBidRequestEvent'], - [EVENTS.BID_ACCEPTED]: ['onBidAcceptedEvent'] + [EVENTS.BID_REQUESTED]: ['onBidRequestEvent'] }).forEach(([ev, [handler, preprocess]]) => { events.on(ev as any, (args) => { preprocess && (preprocess as any)(args); diff --git a/modules/rtdModule/spec.ts b/modules/rtdModule/spec.ts index 7abf38e1247..4dbff40ca2f 100644 --- a/modules/rtdModule/spec.ts +++ b/modules/rtdModule/spec.ts @@ -32,8 +32,7 @@ export type RTDProviderConfig

= BaseConfig

& ( type RTDEvent = typeof EVENTS.AUCTION_INIT | typeof EVENTS.AUCTION_END | typeof EVENTS.BID_RESPONSE | - typeof EVENTS.BID_REQUESTED | - typeof EVENTS.BID_ACCEPTED; + typeof EVENTS.BID_REQUESTED; type EventHandlers

= { [EV in RTDEvent]: (payload: EventPayload, config: RTDProviderConfig

, consent: AllConsentData) => void; diff --git a/modules/scaliburBidAdapter.js b/modules/scaliburBidAdapter.js index b8b05c3ac61..7dce8ee319a 100644 --- a/modules/scaliburBidAdapter.js +++ b/modules/scaliburBidAdapter.js @@ -3,6 +3,7 @@ import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; import {sizesToSizeTuples} from "../src/utils.js"; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'scalibur'; const ENDPOINT_SERVER = new URLSearchParams(window.location.search).get('sclServer') || 'srv'; @@ -115,7 +116,7 @@ export const spec = { ua: ortb2Device.ua, language: ortb2Device.language, sua: ortb2Device.sua || {}, - dnt: ortb2Device.dnt ?? 0, + dnt: getDNT() ? 1 : 0, }, user: { eids, diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index a11820b5897..2f47729de09 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -1,4 +1,3 @@ -import { getDNT } from '../libraries/dnt/index.js'; import { handleCookieSync, PID_STORAGE_NAME, prepareSplitImps } from '../libraries/equativUtils/equativUtils.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -6,6 +5,7 @@ import { config } from '../src/config.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; import { deepAccess, generateUUID, inIframe, isPlainObject, logWarn, mergeDeep } from '../src/utils.js'; +import {getDNT} from '../libraries/dnt/index.js'; const VERSION = '4.3.0'; const BIDDER_CODE = 'sharethrough'; @@ -159,10 +159,6 @@ export const sharethroughAdapterSpec = { const nativeRequest = deepAccess(bidReq, 'mediaTypes.native'); const videoRequest = deepAccess(bidReq, 'mediaTypes.video'); - if (bidderRequest.paapi?.enabled && bidReq.mediaTypes.banner) { - mergeDeep(impression, { ext: { ae: 1 } }); // ae = auction environment; if this is 1, ad server knows we have a fledge auction - } - if (videoRequest) { // default playerSize, only change this if we know width and height are properly defined in the request let [w, h] = [640, 360]; @@ -292,8 +288,6 @@ export const sharethroughAdapterSpec = { return []; } - const fledgeAuctionEnabled = body.ext?.auctionConfigs; - const imp = req.data.imp[0]; const bidsFromExchange = body.seatbid[0].bid.map((bid) => { @@ -340,15 +334,7 @@ export const sharethroughAdapterSpec = { return response; }); - - if (fledgeAuctionEnabled && !isEqtvTest) { - return { - bids: bidsFromExchange, - paapi: body.ext?.auctionConfigs || {}, - }; - } else { - return bidsFromExchange; - } + return bidsFromExchange; }, getUserSyncs: (syncOptions, serverResponses, gdprConsent) => { diff --git a/modules/silverpushBidAdapter.js b/modules/silverpushBidAdapter.js index 46aed11c4ac..9903fd033bb 100644 --- a/modules/silverpushBidAdapter.js +++ b/modules/silverpushBidAdapter.js @@ -117,22 +117,7 @@ export const CONVERTER = ortbConverter({ }, response(buildResponse, bidResponses, ortbResponse, context) { const response = buildResponse(bidResponses, ortbResponse, context); - - let fledgeAuctionConfigs = utils.deepAccess(ortbResponse, 'ext.fledge_auction_configs'); - if (fledgeAuctionConfigs) { - fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { - return Object.assign({ - bidId, - auctionSignals: {} - }, cfg); - }); - return { - bids: response.bids, - paapi: fledgeAuctionConfigs, - } - } else { - return response.bids - } + return response.bids } }); diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index 03199e99d52..23c96a3292a 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -1,13 +1,11 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {deepAccess, deepSetValue, isEmpty, isNumber, logError, logInfo} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; -import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {NATIVE_IMAGE_TYPES} from '../src/constants.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; -import {fill} from '../libraries/appnexusUtils/anUtils.js'; -import {chunk} from '../libraries/chunk/chunk.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -48,30 +46,14 @@ export const spec = { return false; } - if (deepAccess(bid, 'mediaTypes.video.context') === ADPOD) { - logInfo('[SMAATO] Verifying adpod bid request'); - - if (typeof bid.params.adbreakId !== 'string') { - logError('[SMAATO] Missing for adpod request mandatory adbreakId param'); - return false; - } - - if (bid.params.adspaceId) { - logError('[SMAATO] The adspaceId param is not allowed in an adpod bid request'); - return false; - } - } else { - logInfo('[SMAATO] Verifying a non adpod bid request'); - - if (typeof bid.params.adspaceId !== 'string') { - logError('[SMAATO] Missing mandatory adspaceId param'); - return false; - } + if (typeof bid.params.adspaceId !== 'string') { + logError('[SMAATO] Missing mandatory adspaceId param'); + return false; + } - if (bid.params.adbreakId) { - logError('[SMAATO] The adbreakId param is only allowed in an adpod bid request'); - return false; - } + if (bid.params.adbreakId) { + logError('[SMAATO] The adbreakId param is not supported'); + return false; } logInfo('[SMAATO] Verification done, all good'); @@ -147,39 +129,25 @@ export const spec = { } }; - const videoContext = deepAccess(JSON.parse(bidRequest.data).imp[0], 'video.ext.context'); - if (videoContext === ADPOD) { - resultingBid.vastXml = bid.adm; - resultingBid.mediaType = VIDEO; - if (config.getConfig('adpod.brandCategoryExclusion')) { - resultingBid.meta.primaryCatId = bid.cat[0]; - } - resultingBid.video = { - context: ADPOD, - durationSeconds: bid.ext.duration - }; - bids.push(resultingBid); - } else { - switch (smtAdType) { - case 'Img': - case 'Richmedia': - resultingBid.ad = createBannerAd(bid); - resultingBid.mediaType = BANNER; - bids.push(resultingBid); - break; - case 'Video': - resultingBid.vastXml = bid.adm; - resultingBid.mediaType = VIDEO; - bids.push(resultingBid); - break; - case 'Native': - resultingBid.native = createNativeAd(bid.adm); - resultingBid.mediaType = NATIVE; - bids.push(resultingBid); - break; - default: - logInfo('[SMAATO] Invalid ad type:', smtAdType); - } + switch (smtAdType) { + case 'Img': + case 'Richmedia': + resultingBid.ad = createBannerAd(bid); + resultingBid.mediaType = BANNER; + bids.push(resultingBid); + break; + case 'Video': + resultingBid.vastXml = bid.adm; + resultingBid.mediaType = VIDEO; + bids.push(resultingBid); + break; + case 'Native': + resultingBid.native = createNativeAd(bid.adm); + resultingBid.mediaType = NATIVE; + bids.push(resultingBid); + break; + default: + logInfo('[SMAATO] Invalid ad type:', smtAdType); } resultingBid.meta.mediaType = resultingBid.mediaType; }); @@ -247,15 +215,6 @@ const converter = ortbConverter({ const request = buildRequest(imps, bidderRequest, context); const bidRequest = context.bidRequests[0]; - let content; - const mediaType = context.mediaType; - if (mediaType === VIDEO) { - const videoParams = bidRequest.mediaTypes[VIDEO]; - if (videoParams.context === ADPOD) { - request.imp = createAdPodImp(request.imp[0], videoParams); - content = addOptionalAdpodParameters(videoParams); - } - } request.at = 1; @@ -275,15 +234,9 @@ const converter = ortbConverter({ if (request.site) { request.site.id = window.location.hostname - if (content) { - request.site.content = content; - } setPublisherId(request.site); } else if (request.dooh) { request.dooh.id = window.location.hostname - if (content) { - request.dooh.content = content; - } setPublisherId(request.dooh); } else { request.site = { @@ -291,7 +244,7 @@ const converter = ortbConverter({ domain: bidderRequest.refererInfo.domain || window.location.hostname, page: bidderRequest.refererInfo.page || window.location.href, ref: bidderRequest.refererInfo.ref, - content: content || null + content: null } setPublisherId(request.site); } @@ -362,7 +315,6 @@ const converter = ortbConverter({ imp: { banner(orig, imp, bidRequest, context) { const mediaType = context.mediaType; - if (mediaType === BANNER) { imp.bidfloor = getBidFloor(bidRequest, BANNER, getAdUnitSizes(bidRequest)); } @@ -375,11 +327,9 @@ const converter = ortbConverter({ if (mediaType === VIDEO) { const videoParams = bidRequest.mediaTypes[VIDEO]; imp.bidfloor = getBidFloor(bidRequest, VIDEO, videoParams.playerSize); - if (videoParams.context !== ADPOD) { - deepSetValue(imp, 'video.ext', { - rewarded: videoParams.ext && videoParams.ext.rewarded ? videoParams.ext.rewarded : 0 - }) - } + deepSetValue(imp, 'video.ext', { + rewarded: videoParams.ext && videoParams.ext.rewarded ? videoParams.ext.rewarded : 0 + }) } orig(imp, bidRequest, context); @@ -387,7 +337,6 @@ const converter = ortbConverter({ native(orig, imp, bidRequest, context) { const mediaType = context.mediaType; - if (mediaType === NATIVE) { imp.bidfloor = getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(bidRequest.nativeOrtbRequest)); } @@ -431,81 +380,6 @@ function getNativeMainImageSize(nativeRequest) { return [] } -function createAdPodImp(imp, videoMediaType) { - const bce = config.getConfig('adpod.brandCategoryExclusion') - imp.video.ext = { - context: ADPOD, - brandcategoryexclusion: bce !== undefined && bce - }; - - const numberOfPlacements = getAdPodNumberOfPlacements(videoMediaType) - const imps = fill(imp, numberOfPlacements) - - const durationRangeSec = videoMediaType.durationRangeSec - if (videoMediaType.requireExactDuration) { - // equal distribution of numberOfPlacement over all available durations - const divider = Math.ceil(numberOfPlacements / durationRangeSec.length) - const chunked = chunk(imps, divider) - - // each configured duration is set as min/maxduration for a subset of requests - durationRangeSec.forEach((duration, index) => { - chunked[index].forEach(imp => { - const sequence = index + 1; - imp.video.minduration = duration - imp.video.maxduration = duration - imp.video.sequence = sequence - }); - }); - } else { - // all maxdurations should be the same - const maxDuration = Math.max(...durationRangeSec); - imps.forEach((imp, index) => { - const sequence = index + 1; - imp.video.maxduration = maxDuration - imp.video.sequence = sequence - }); - } - - return imps -} - -function getAdPodNumberOfPlacements(videoMediaType) { - const {adPodDurationSec, durationRangeSec, requireExactDuration} = videoMediaType - const minAllowedDuration = Math.min(...durationRangeSec) - const numberOfPlacements = Math.floor(adPodDurationSec / minAllowedDuration) - - return requireExactDuration - ? Math.max(numberOfPlacements, durationRangeSec.length) - : numberOfPlacements -} - -const addOptionalAdpodParameters = (videoMediaType) => { - const content = {} - - if (videoMediaType.tvSeriesName) { - content.series = videoMediaType.tvSeriesName - } - if (videoMediaType.tvEpisodeName) { - content.title = videoMediaType.tvEpisodeName - } - if (typeof videoMediaType.tvSeasonNumber === 'number') { - content.season = videoMediaType.tvSeasonNumber.toString() // conversion to string as in OpenRTB season is a string - } - if (typeof videoMediaType.tvEpisodeNumber === 'number') { - content.episode = videoMediaType.tvEpisodeNumber - } - if (typeof videoMediaType.contentLengthSec === 'number') { - content.len = videoMediaType.contentLengthSec - } - if (videoMediaType.contentMode && ['live', 'on-demand'].indexOf(videoMediaType.contentMode) >= 0) { - content.livestream = videoMediaType.contentMode === 'live' ? 1 : 0 - } - - if (!isEmpty(content)) { - return content - } -} - function getBidFloor(bidRequest, mediaType, sizes) { if (typeof bidRequest.getFloor === 'function') { const size = sizes.length === 1 ? sizes[0] : '*'; diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js index 00f8616a665..9c4460b108a 100644 --- a/modules/smartxBidAdapter.js +++ b/modules/smartxBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { logError, deepAccess, @@ -21,6 +20,7 @@ import { import { VIDEO } from '../src/mediaTypes.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/snigelBidAdapter.js b/modules/snigelBidAdapter.js index 29534ae7318..3349ed737eb 100644 --- a/modules/snigelBidAdapter.js +++ b/modules/snigelBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {deepAccess, isArray, isFn, isPlainObject, inIframe, generateUUID} from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import { getViewportSize } from '../libraries/viewport/viewport.js'; +import {getDNT} from '../libraries/dnt/index.js'; const BIDDER_CODE = 'snigel'; const GVLID = 1076; diff --git a/modules/sspBCBidAdapter.js b/modules/sspBCBidAdapter.js index 5ce8fb34492..3efc17138e2 100644 --- a/modules/sspBCBidAdapter.js +++ b/modules/sspBCBidAdapter.js @@ -1,11 +1,11 @@ -import { deepAccess, getWinDimensions, getWindowTop, isArray, logInfo, logWarn } from '../src/utils.js'; -import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRatio.js'; -import { ajax } from '../src/ajax.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import {deepAccess, getWinDimensions, getWindowTop, isArray, logInfo, logWarn} from '../src/utils.js'; +import {getDevicePixelRatio} from '../libraries/devicePixelRatio/devicePixelRatio.js'; +import {ajax} from '../src/ajax.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js'; +import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; +import {getCurrencyFromBidderRequest} from '../libraries/ortb2Utils/currency.js'; const BIDDER_CODE = 'sspBC'; const BIDDER_URL = 'https://ssp.wp.pl/bidder/'; @@ -671,8 +671,7 @@ const spec = { interpretResponse(serverResponse, request) { const { bidderRequest } = request; const { body: response = {} } = serverResponse; - const { seatbid: responseSeat, ext: responseExt = {} } = response; - const { paapi: fledgeAuctionConfigs = [] } = responseExt; + const { seatbid: responseSeat } = response; const bids = []; let site = JSON.parse(request.data).site; // get page and referer data from request site.sn = response.sn || 'mc_adapter'; // WPM site name (wp_sn) @@ -788,7 +787,7 @@ const spec = { }); } - return fledgeAuctionConfigs.length ? { bids, fledgeAuctionConfigs } : bids; + return bids; }, getUserSyncs(syncOptions, _, gdprConsent = {}) { diff --git a/modules/storageControl.ts b/modules/storageControl.ts index 93411fba3ac..2b5f5db2cdd 100644 --- a/modules/storageControl.ts +++ b/modules/storageControl.ts @@ -116,7 +116,7 @@ export function storageControlRule(getEnforcement = () => enforcement, check = c const {disclosed, parent, reason} = check(params); if (disclosed === null) return; if (!disclosed) { - const enforcement = getEnforcement(); + const enforcement = getEnforcement() ?? ENFORCE_STRICT; if (enforcement === ENFORCE_STRICT || (enforcement === ENFORCE_ALIAS && !parent)) return {allow: false, reason}; if (reason) { logWarn('storageControl:', reason); @@ -125,14 +125,19 @@ export function storageControlRule(getEnforcement = () => enforcement, check = c } } -registerActivityControl(ACTIVITY_ACCESS_DEVICE, 'storageControl', storageControlRule()); +const rule = registerActivityControl(ACTIVITY_ACCESS_DEVICE, 'storageControl', storageControlRule()); + +export function deactivate() { + // turn off this module; should only be used in testing + rule(); +} export type StorageControlConfig = { /** - * - 'off': logs a warning when an undisclosed storage key is used - * - 'strict': deny access to undisclosed storage keys + * - 'strict': deny access to undisclosed storage keys (default) * - 'allowAliases': deny access to undisclosed storage keys, unless the use is from an alias of a module that does * disclose them + * - 'off': logs a warning when an undisclosed storage key is used */ enforcement?: typeof ENFORCE_OFF | typeof ENFORCE_ALIAS | typeof ENFORCE_STRICT; } @@ -144,7 +149,7 @@ declare module '../src/config' { } config.getConfig('storageControl', (cfg) => { - enforcement = cfg?.storageControl?.enforcement ?? ENFORCE_OFF; + enforcement = cfg?.storageControl?.enforcement ?? ENFORCE_STRICT; }) export function dynamicDisclosureCollector() { diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index 421ddbd256b..3b39dd3db03 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -3,7 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; -import {deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject, getWinDimensions} from '../src/utils.js'; +import {deepSetValue, getWinDimensions, getWindowSelf, isPlainObject, replaceAuctionPrice} from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import {ajax} from '../src/ajax.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js'; @@ -236,58 +236,11 @@ export const spec = { return []; } const bids = []; - const fledgeAuctionConfigs = []; if (!serverResponse.body.seatbid || !serverResponse.body.seatbid.length || !serverResponse.body.seatbid[0].bid || !serverResponse.body.seatbid[0].bid.length) { - if (!serverResponse.body.ext || !serverResponse.body.ext.igbid || !serverResponse.body.ext.igbid.length) { - return []; - } + return []; } else { bids.push(...converter.fromORTB({response: serverResponse.body, request: request.data}).bids); } - if (isArray(serverResponse.body.ext?.igbid)) { - serverResponse.body.ext.igbid.forEach((igbid) => { - if (!igbid || !igbid.igbuyer || !igbid.igbuyer.length || !igbid.igbuyer[0].buyerdata) { - return; - } - const buyerdata = safeJSONParse(igbid.igbuyer[0]?.buyerdata) - if (!buyerdata) { - return; - } - const perBuyerSignals = {}; - igbid.igbuyer.forEach(buyerItem => { - if (!buyerItem || !buyerItem.buyerdata || !buyerItem.origin) { - return; - } - const parsedData = safeJSONParse(buyerItem.buyerdata) - if (!parsedData || !parsedData.perBuyerSignals || !(buyerItem.origin in parsedData.perBuyerSignals)) { - return; - } - perBuyerSignals[buyerItem.origin] = parsedData.perBuyerSignals[buyerItem.origin]; - }); - const impId = igbid?.impid; - fledgeAuctionConfigs.push({ - impId, - config: { - seller: buyerdata?.seller, - resolveToConfig: buyerdata?.resolveToConfig, - sellerSignals: {}, - sellerTimeout: buyerdata?.sellerTimeout, - perBuyerSignals, - auctionSignals: {}, - decisionLogicUrl: buyerdata?.decisionLogicUrl, - interestGroupBuyers: buyerdata?.interestGroupBuyers, - perBuyerTimeouts: buyerdata?.perBuyerTimeouts, - }, - }); - }); - } - - if (fledgeAuctionConfigs.length) { - return { - bids, - paapi: fledgeAuctionConfigs, - }; - } return bids; }, onBidWon: (bid) => { diff --git a/modules/tappxBidAdapter.js b/modules/tappxBidAdapter.js index 6ca3adb4d54..561b02e6a9a 100644 --- a/modules/tappxBidAdapter.js +++ b/modules/tappxBidAdapter.js @@ -1,12 +1,12 @@ 'use strict'; -import {getDNT} from '../libraries/dnt/index.js'; import { logWarn, deepAccess, isFn, isPlainObject, isBoolean, isNumber, isStr, isArray } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { parseDomain } from '../src/refererDetection.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index dbdda501658..17fec332a02 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -201,7 +201,6 @@ function getSharedViewerIdParameters(validBidRequests) { id5Id: 'id5-sync.com', // id5IdSystem criteoId: 'criteo.com', // criteoIdSystem yahooConnectId: 'yahoo.com', // connectIdSystem - quantcastId: 'quantcast.com', // quantcastIdSystem epsilonPublisherLinkId: 'epsilon.com', // publinkIdSystem publisherFirstPartyViewerId: 'pubcid.org', // sharedIdSystem merkleId: 'merkleinc.com', // merkleIdSystem diff --git a/modules/theAdxBidAdapter.js b/modules/theAdxBidAdapter.js index d57e307c7e1..2e8b3549365 100644 --- a/modules/theAdxBidAdapter.js +++ b/modules/theAdxBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { logInfo, isEmpty, deepAccess, parseUrl, parseSizesInput, _map } from '../src/utils.js'; import { BANNER, @@ -10,6 +9,7 @@ import { } from '../src/adapters/bidderFactory.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/topLevelPaapi.js b/modules/topLevelPaapi.js deleted file mode 100644 index 3fb613ff728..00000000000 --- a/modules/topLevelPaapi.js +++ /dev/null @@ -1,207 +0,0 @@ -import {submodule} from '../src/hook.js'; -import {config} from '../src/config.js'; -import {logError, logInfo, logWarn, mergeDeep} from '../src/utils.js'; -import {auctionStore} from '../libraries/weakStore/weakStore.js'; -import {getGlobal} from '../src/prebidGlobal.js'; -import {emit} from '../src/events.js'; -import {BID_STATUS, EVENTS} from '../src/constants.js'; -import {PbPromise} from '../src/utils/promise.js'; -import {getBidToRender, getRenderingData, markWinningBid} from '../src/adRendering.js'; - -let getPAAPIConfig, expandFilters, moduleConfig; - -const paapiBids = auctionStore(); -const MODULE_NAME = 'topLevelPaapi'; - -config.getConfig('paapi', (cfg) => { - moduleConfig = cfg.paapi?.topLevelSeller; - if (moduleConfig) { - getBidToRender.before(renderPaapiHook); - getRenderingData.before(getRenderingDataHook); - markWinningBid.before(markWinningBidHook); - } else { - getBidToRender.getHooks({hook: renderPaapiHook}).remove(); - getRenderingData.getHooks({hook: getRenderingDataHook}).remove(); - markWinningBid.getHooks({hook: markWinningBidHook}).remove(); - } -}); - -function isPaapiBid(bid) { - return bid?.source === 'paapi'; -} - -function bidIfRenderable(bid) { - if (bid && !bid.urn) { - logWarn(MODULE_NAME, 'rendering in fenced frames is not supported. Consider using resolveToConfig: false', bid); - return; - } - return bid; -} - -function renderPaapiHook(next, adId, forRender = true, cb) { - PbPromise - .resolve() - .then(() => { - const ids = parsePaapiAdId(adId); - if (ids) { - const [auctionId, adUnitCode] = ids; - return paapiBids(auctionId)?.[adUnitCode]?.then(bid => { - if (!bid) { - logWarn(MODULE_NAME, `No PAAPI bid found for auctionId: "${auctionId}", adUnit: "${adUnitCode}"`); - } - return bidIfRenderable(bid); - }); - } - }) - .then((bid) => { - if (bid != null) return bid; - return new Promise(resolve => next(adId, forRender, resolve)) - }) - .then((bid) => { - if (bid == null || isPaapiBid(bid) || bid?.status === BID_STATUS.RENDERED) return bid; - return getPAAPIBids({adUnitCode: bid.adUnitCode}).then(res => { - const paapiBid = bidIfRenderable(res[bid.adUnitCode]); - if (paapiBid) { - if (!forRender) return paapiBid; - if (forRender && paapiBid.status !== BID_STATUS.RENDERED) { - paapiBid.overriddenAdId = bid.adId; - logInfo(MODULE_NAME, 'overriding contextual bid with PAAPI bid', bid, paapiBid) - return paapiBid; - } - } - return bid; - }); - }) - .then(cb); -} - -export function getRenderingDataHook(next, bid, options) { - if (isPaapiBid(bid)) { - next.bail({ - width: bid.width, - height: bid.height, - adUrl: bid.urn - }); - } else { - next(bid, options); - } -} - -export function markWinningBidHook(next, bid) { - if (isPaapiBid(bid)) { - emit(EVENTS.BID_WON, bid); - next.bail(); - } else { - next(bid); - } -} - -function getBaseAuctionConfig() { - if (moduleConfig?.auctionConfig) { - return Object.assign({ - resolveToConfig: false - }, moduleConfig.auctionConfig); - } -} - -function onAuctionConfig(auctionId, auctionConfigs) { - const base = getBaseAuctionConfig(); - if (base) { - Object.entries(auctionConfigs).forEach(([adUnitCode, auctionConfig]) => { - mergeDeep(auctionConfig, base); - if (moduleConfig.autorun ?? true) { - getPAAPIBids({adUnitCode, auctionId}); - } - }); - } -} - -export function parsePaapiSize(size) { - /* From https://github.com/WICG/turtledove/blob/main/FLEDGE.md#12-interest-group-attributes: - * Each size has the format {width: widthVal, height: heightVal}, - * where the values can have either pixel units (e.g. 100 or '100px') or screen dimension coordinates (e.g. 100sw or 100sh). - */ - if (typeof size === 'number') return size; - if (typeof size === 'string') { - const px = /^(\d+)(px)?$/.exec(size)?.[1]; - if (px) { - return parseInt(px, 10); - } - } - return null; -} - -export function getPaapiAdId(auctionId, adUnitCode) { - return `paapi:/${auctionId.replace(/:/g, '::')}/:/${adUnitCode.replace(/:/g, '::')}`; -} - -export function parsePaapiAdId(adId) { - const match = /^paapi:\/(.*)\/:\/(.*)$/.exec(adId); - if (match) { - return [match[1], match[2]].map(s => s.replace(/::/g, ':')); - } -} - -/** - * Returns the PAAPI runAdAuction result for the given filters, as a map from ad unit code to auction result - * (an object with `width`, `height`, and one of `urn` or `frameConfig`). - * - * @param filters - * @param raa - * @return {Promise<{[p: string]: any}>} - */ -export function getPAAPIBids(filters, raa = (...args) => navigator.runAdAuction(...args)) { - return Promise.all( - Object.entries(expandFilters(filters)) - .map(([adUnitCode, auctionId]) => { - const bids = paapiBids(auctionId); - if (bids && !bids.hasOwnProperty(adUnitCode)) { - const auctionConfig = getPAAPIConfig({adUnitCode, auctionId})[adUnitCode]; - if (auctionConfig) { - emit(EVENTS.RUN_PAAPI_AUCTION, { - auctionId, - adUnitCode, - auctionConfig - }); - bids[adUnitCode] = new Promise((resolve, reject) => raa(auctionConfig).then(resolve, reject)) - .then(result => { - if (result) { - const bid = { - source: 'paapi', - adId: getPaapiAdId(auctionId, adUnitCode), - width: parsePaapiSize(auctionConfig.requestedSize?.width), - height: parsePaapiSize(auctionConfig.requestedSize?.height), - adUnitCode, - auctionId, - [typeof result === 'string' ? 'urn' : 'frameConfig']: result, - auctionConfig, - }; - emit(EVENTS.PAAPI_BID, bid); - return bid; - } else { - emit(EVENTS.PAAPI_NO_BID, {auctionId, adUnitCode, auctionConfig}); - return null; - } - }).catch(error => { - logError(MODULE_NAME, `error (auction "${auctionId}", adUnit "${adUnitCode}"):`, error); - emit(EVENTS.PAAPI_ERROR, {auctionId, adUnitCode, error, auctionConfig}); - return null; - }); - } - } - return bids?.[adUnitCode]?.then(res => [adUnitCode, res]); - }).filter(e => e) - ).then(result => Object.fromEntries(result)); -} - -getGlobal().getPAAPIBids = (filters) => getPAAPIBids(filters); - -export const topLevelPAAPI = { - name: MODULE_NAME, - init(params) { - getPAAPIConfig = params.getPAAPIConfig; - expandFilters = params.expandFilters; - }, - onAuctionConfig -}; -submodule('paapi', topLevelPAAPI); diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 503edaa8864..f5b5de0097d 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -58,10 +58,6 @@ export const tripleliftAdapterSpec = { tlCall = tryAppendQueryString(tlCall, 'us_privacy', bidderRequest.uspConsent); } - if (bidderRequest?.paapi?.enabled) { - tlCall = tryAppendQueryString(tlCall, 'fledge', bidderRequest.paapi.enabled); - } - if (config.getConfig('coppa') === true) { tlCall = tryAppendQueryString(tlCall, 'coppa', true); } @@ -81,26 +77,8 @@ export const tripleliftAdapterSpec = { interpretResponse: function(serverResponse, {bidderRequest}) { let bids = serverResponse.body.bids || []; - const paapi = serverResponse.body.paapi || []; - - bids = bids.map(bid => _buildResponseObject(bidderRequest, bid)); - if (paapi.length > 0) { - const fledgeAuctionConfigs = paapi.map(config => { - return { - bidId: bidderRequest.bids[config.imp_id].bidId, - config: config.auctionConfig - }; - }); - - logMessage('Response with FLEDGE:', { bids, fledgeAuctionConfigs }); - return { - bids, - paapi: fledgeAuctionConfigs - }; - } else { - return bids; - } + return bids.map(bid => _buildResponseObject(bidderRequest, bid)); }, getUserSyncs: function(syncOptions, responses, gdprConsent, usPrivacy, gppConsent) { diff --git a/modules/ttdBidAdapter.js b/modules/ttdBidAdapter.js index 4598c3b8a7a..a73baa4af1f 100644 --- a/modules/ttdBidAdapter.js +++ b/modules/ttdBidAdapter.js @@ -3,8 +3,8 @@ import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { isNumber } from '../src/utils.js'; -import { getDNT } from '../libraries/dnt/index.js'; import { getConnectionType } from '../libraries/connectionInfo/connectionUtils.js' +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/ucfunnelBidAdapter.js b/modules/ucfunnelBidAdapter.js index f73bd470b14..8eda650ee09 100644 --- a/modules/ucfunnelBidAdapter.js +++ b/modules/ucfunnelBidAdapter.js @@ -1,10 +1,10 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { generateUUID, _each, deepAccess } from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index 18926496258..f2934d32f10 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -1,4 +1,3 @@ -import {getDNT} from '../libraries/dnt/index.js'; import { deepAccess, deepSetValue, @@ -18,6 +17,7 @@ import { import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { Renderer } from '../src/Renderer.js'; +import {getDNT} from '../libraries/dnt/index.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest diff --git a/src/adRendering.ts b/src/adRendering.ts index 25aba25a59f..c031a8555bd 100644 --- a/src/adRendering.ts +++ b/src/adRendering.ts @@ -56,15 +56,6 @@ declare module './events' { } } -/** - * NOTE: this is here to support PAAPI, which is soon to be removed; - * and should *not* be made asynchronous or it breaks `legacyRender` (unyielding) - * rendering logic - */ -export const getBidToRender = hook('sync', function (adId, forRender, cb) { - cb(auctionManager.findBidByAdId(adId)); -}) - export const markWinningBid = hook('sync', function (bid) { (parseEventTrackers(bid.eventtrackers)[EVENT_TYPE_WIN]?.[TRACKER_METHOD_IMG] || []) .forEach(url => triggerPixel(url)); @@ -399,10 +390,8 @@ export const renderAdDirect = yieldsIf(() => !legacyRender, function renderAdDir if (!adId || !doc) { fail(AD_RENDER_FAILED_REASON.MISSING_DOC_OR_ADID, `missing ${adId ? 'doc' : 'adId'}`); } else { - getBidToRender(adId, true, (bidResponse) => { - bid = bidResponse; - handleRender({renderFn, resizeFn, adId, options: {clickUrl: options?.clickThrough}, bidResponse, doc}); - }); + bid = auctionManager.findBidByAdId(adId) + handleRender({renderFn, resizeFn, adId, options: {clickUrl: options?.clickThrough}, bidResponse: bid, doc}); } } catch (e) { fail(EXCEPTION, e.message); diff --git a/src/adapters/bidderFactory.ts b/src/adapters/bidderFactory.ts index 60f21964f88..1d97253e9e6 100644 --- a/src/adapters/bidderFactory.ts +++ b/src/adapters/bidderFactory.ts @@ -319,14 +319,6 @@ export function newBidder(spec: BidderSpec) { onTimelyResponse(spec.code); responses.push(resp) }, - onPaapi: (paapiConfig: any) => { - const bidRequest = bidRequestMap[paapiConfig.bidId]; - if (bidRequest) { - addPaapiConfig(bidRequest, paapiConfig); - } else { - logWarn('Received fledge auction configuration for an unknown bidId', paapiConfig); - } - }, // If the server responds with an error, there's not much we can do beside logging. onError: (errorMessage, error) => { if (!error.timedOut) { @@ -390,7 +382,12 @@ export function newBidder(spec: BidderSpec) { } } -const RESPONSE_PROPS = ['bids', 'paapi'] +const RESPONSE_PROPS = [ + 'bids', + // allow bid adapters to still reply with paapi (which will be ignored). + 'paapi', +] + /** * Run a set of bid requests - that entails converting them to HTTP requests, sending * them over the network, and parsing the responses. @@ -407,7 +404,7 @@ export const processBidderRequests = hook('async', function, ajax: Ajax, wrapCallback: (fn: T) => Wraps, - {onRequest, onResponse, onPaapi, onError, onBid, onCompletion}: { + {onRequest, onResponse, onError, onBid, onCompletion}: { /** * invoked once for each HTTP request built by the adapter - with the raw request */ @@ -424,10 +421,6 @@ export const processBidderRequests = hook('async', function void; - /** - * invoked once with each member of the adapter response's 'paapi' array. - */ - onPaapi: (paapi: unknown) => void; /** * invoked once when all bid requests have been processed */ @@ -483,16 +476,12 @@ export const processBidderRequests = hook('async', function !RESPONSE_PROPS.includes(key))) { bids = response.bids; - paapiConfigs = response.paapi; } else { bids = response; } - if (isArray(paapiConfigs)) { - paapiConfigs.forEach(onPaapi); - } if (bids) { if (isArray(bids)) { bids.forEach(addBid); @@ -616,9 +605,6 @@ export const registerSyncInner = hook('async', function(spec: BidderSpec { -}, 'addPaapiConfig'); - declare module '../bidfactory' { interface BannerBidProperties { width?: number; diff --git a/src/ajax.ts b/src/ajax.ts index 58ed89b6e83..b745c8e2b4e 100644 --- a/src/ajax.ts +++ b/src/ajax.ts @@ -53,10 +53,6 @@ export interface AjaxOptions { * Whether chrome's `Sec-Browing-Topics` header should be sent */ browsingTopics?: boolean - /** - * Whether chrome's PAAPI headers should be sent. - */ - adAuctionHeaders?: boolean; /** * If true, suppress warnings */ @@ -94,8 +90,8 @@ export function toFetchRequest(url, data, options: AjaxOptions = {}) { rqOpts.credentials = 'include'; } if (isSecureContext) { - ['browsingTopics', 'adAuctionHeaders'].forEach(opt => { - // the Request constructor will throw an exception if the browser supports topics/fledge + ['browsingTopics'].forEach(opt => { + // the Request constructor will throw an exception if the browser supports topics // but we're not in a secure context if (options[opt]) { rqOpts[opt] = true; diff --git a/src/auction.ts b/src/auction.ts index a6912be69be..dff01d6421b 100644 --- a/src/auction.ts +++ b/src/auction.ts @@ -100,10 +100,6 @@ declare module './events' { * Fired when an auction times out. */ [EVENTS.BID_TIMEOUT]: [BidRequest[]]; - /** - * Fired when a bid is received. - */ - [EVENTS.BID_ACCEPTED]: [Partial]; /** * Fired when a bid is rejected. */ @@ -428,8 +424,8 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a adapterManager.callSetTargetingBidder(bid.adapterCode || bid.bidder, bid); } - events.on(EVENTS.SEAT_NON_BID, (event) => { - if (event.auctionId === _auctionId) { + events.on(EVENTS.PBS_ANALYTICS, (event) => { + if (event.auctionId === _auctionId && event.seatnonbid != null) { addNonBids(event.seatnonbid) } }); @@ -530,7 +526,6 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM function acceptBidResponse(adUnitCode: string, bid: Partial) { handleBidResponse(adUnitCode, bid, (done) => { const bidResponse = getPreparedBidForAuction(bid); - events.emit(EVENTS.BID_ACCEPTED, bidResponse); if ((FEATURES.VIDEO && bidResponse.mediaType === VIDEO) || (FEATURES.AUDIO && bidResponse.mediaType === AUDIO)) { tryAddVideoAudioBid(auctionInstance, bidResponse, done); } else { diff --git a/src/constants.ts b/src/constants.ts index 6380d89f712..5c4c0a6f00f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -25,7 +25,6 @@ export const EVENTS = { BID_RESPONSE: 'bidResponse', BID_REJECTED: 'bidRejected', NO_BID: 'noBid', - SEAT_NON_BID: 'seatNonBid', BID_WON: 'bidWon', BIDDER_DONE: 'bidderDone', BIDDER_ERROR: 'bidderError', @@ -33,7 +32,6 @@ export const EVENTS = { BEFORE_REQUEST_BIDS: 'beforeRequestBids', BEFORE_BIDDER_HTTP: 'beforeBidderHttp', REQUEST_BIDS: 'requestBids', - ADD_AD_UNITS: 'addAdUnits', AD_RENDER_FAILED: 'adRenderFailed', AD_RENDER_SUCCEEDED: 'adRenderSucceeded', TCF2_ENFORCEMENT: 'tcf2Enforcement', @@ -42,12 +40,7 @@ export const EVENTS = { STALE_RENDER: 'staleRender', EXPIRED_RENDER: 'expiredRender', BILLABLE_EVENT: 'billableEvent', - BID_ACCEPTED: 'bidAccepted', - RUN_PAAPI_AUCTION: 'paapiRunAuction', PBS_ANALYTICS: 'pbsAnalytics', - PAAPI_BID: 'paapiBid', - PAAPI_NO_BID: 'paapiNoBid', - PAAPI_ERROR: 'paapiError', BEFORE_PBS_HTTP: 'beforePBSHttp', BROWSI_INIT: 'browsiInit', BROWSI_DATA: 'browsiData', diff --git a/src/fpd/enrichment.ts b/src/fpd/enrichment.ts index 1ccaaaf6692..2780ba2d09d 100644 --- a/src/fpd/enrichment.ts +++ b/src/fpd/enrichment.ts @@ -12,7 +12,6 @@ import { mergeDeep, memoize } from '../utils.js'; -import { getDNT } from '../../libraries/dnt/index.js'; import {config} from '../config.js'; import {getHighEntropySUA, getLowEntropySUA} from './sua.js'; import {PbPromise} from '../utils/promise.js'; @@ -158,7 +157,6 @@ const ENRICHMENTS = { const device = { w, h, - dnt: getDNT() ? 1 : 0, ua: win.navigator.userAgent, language: win.navigator.language.split('-').shift(), ext: { diff --git a/src/prebid.ts b/src/prebid.ts index 34d6208970a..e662a0e178c 100644 --- a/src/prebid.ts +++ b/src/prebid.ts @@ -70,7 +70,7 @@ const pbjsInstance = getGlobal(); const { triggerUserSyncs } = userSync; /* private variables */ -const { ADD_AD_UNITS, REQUEST_BIDS, SET_TARGETING } = EVENTS; +const { REQUEST_BIDS, SET_TARGETING } = EVENTS; // initialize existing debugging sessions if present loadSession(); @@ -954,21 +954,12 @@ export function executeCallbacks(fn, reqBidsConfigObj) { // This hook will execute all storage callbacks which were registered before gdpr enforcement hook was added. Some bidders, user id modules use storage functions when module is parsed but gdpr enforcement hook is not added at that stage as setConfig callbacks are yet to be called. Hence for such calls we execute all the stored callbacks just before requestBids. At this hook point we will know for sure that tcfControl module is added or not requestBids.before(executeCallbacks, 49); -declare module './events' { - interface Events { - /** - * Fired when `.addAdUniuts` is called. - */ - [ADD_AD_UNITS]: []; - } -} /** * Add ad unit(s) * @param adUnits */ function addAdUnits(adUnits: AdUnitDefinition | AdUnitDefinition[]) { pbjsInstance.adUnits.push(...(Array.isArray(adUnits) ? adUnits : [adUnits])) - events.emit(ADD_AD_UNITS); } addApiMethod('addAdUnits', addAdUnits); diff --git a/src/secureCreatives.js b/src/secureCreatives.js index 8233c373d1a..a385113e54e 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -8,7 +8,6 @@ import {BID_STATUS, MESSAGES} from './constants.js'; import {isApnGetTagDefined, isGptPubadsDefined, logError, logWarn} from './utils.js'; import { deferRendering, - getBidToRender, handleCreativeEvent, handleNativeMessage, handleRender, @@ -16,6 +15,7 @@ import { } from './adRendering.js'; import {getCreativeRendererSource, PUC_MIN_VERSION} from './creativeRenderers.js'; import {PbPromise} from './utils/promise.js'; +import {auctionManager} from './auctionManager.js'; const { REQUEST, RESPONSE, NATIVE, EVENT } = MESSAGES; @@ -70,10 +70,8 @@ export function receiveMessage(ev, cb) { } if (data && data.adId && data.message && HANDLER_MAP.hasOwnProperty(data.message)) { - return getBidToRender(data.adId, data.message === MESSAGES.REQUEST, (adObject) => { - HANDLER_MAP[data.message](ensureAdId(data.adId, getReplier(ev)), data, adObject); - cb && cb(); - }); + HANDLER_MAP[data.message](ensureAdId(data.adId, getReplier(ev)), data, auctionManager.findBidByAdId(data.adId)); + cb && cb(); } } diff --git a/src/targeting.ts b/src/targeting.ts index 477ddaab7f0..49d72f7c023 100644 --- a/src/targeting.ts +++ b/src/targeting.ts @@ -5,7 +5,6 @@ import {config} from './config.js'; import {BID_STATUS, DEFAULT_TARGETING_KEYS, EVENTS, JSON_MAPPING, TARGETING_KEYS} from './constants.js'; import * as events from './events.js'; import {hook} from './hook.js'; -import {ADPOD} from './mediaTypes.js'; import { deepAccess, deepClone, @@ -663,7 +662,7 @@ export function newTargeting(auctionManager) { const cacheFilter = bidCacheEnabled || isBidFromLastAuction; const bidFilter = cacheFilter && filterFunctionResult; - if (bidFilter && bid?.video?.context !== ADPOD && isBidUsable(bid)) { + if (bidFilter && isBidUsable(bid)) { bid.latestTargetedAuctionId = latestAuctionForAdUnit[bid.adUnitCode]; bids.push(bid) } diff --git a/src/utils.js b/src/utils.js index ec30b934a49..973015336ba 100644 --- a/src/utils.js +++ b/src/utils.js @@ -760,7 +760,7 @@ export function groupBy(xs, key) { */ export function isValidMediaTypes(mediaTypes) { const SUPPORTED_MEDIA_TYPES = ['banner', 'native', 'video', 'audio']; - const SUPPORTED_STREAM_TYPES = ['instream', 'outstream', 'adpod']; + const SUPPORTED_STREAM_TYPES = ['instream', 'outstream']; const types = Object.keys(mediaTypes); diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 6ebb8666096..b3a10ede626 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -836,7 +836,7 @@ describe('auctionmanager.js', function () { } const auction = auctionManager.createAuction({adUnits, ortb2Fragments}); expect(auction.getNonBids()[0]).to.equal(undefined); - events.emit(EVENTS.SEAT_NON_BID, { + events.emit(EVENTS.PBS_ANALYTICS, { auctionId: auction.getAuctionId(), seatnonbid: ['test'] }); diff --git a/test/spec/libraries/dnt_spec.js b/test/spec/libraries/dnt_spec.js deleted file mode 100644 index 177542dca31..00000000000 --- a/test/spec/libraries/dnt_spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import {getDNT} from '../../../libraries/dnt/index.js'; - -describe('dnt helper', () => { - let win; - beforeEach(() => { - win = {}; - }); - - [ - 'top', - 'doNotTrack', - 'navigator', - 'navigator.doNotTrack', - 'top.doNotTrack', - 'top.navigator.doNotTrack' - ].forEach(path => { - it(`should not choke if ${path} throws`, () => { - path = path.split('.'); - path.reduce((parent, name, i) => { - if (i === path.length - 1) { - Object.defineProperty(parent, name, { - get() { - throw new Error(); - } - }) - } else { - parent = parent[name] = {}; - } - return parent; - }, win); - expect(getDNT(win)).to.be.false; - }) - }) -}) diff --git a/test/spec/libraries/storageDisclosure_spec.js b/test/spec/libraries/storageDisclosure_spec.js index 1f848504ee2..8020b41a233 100644 --- a/test/spec/libraries/storageDisclosure_spec.js +++ b/test/spec/libraries/storageDisclosure_spec.js @@ -1,5 +1,4 @@ import {getStorageDisclosureSummary} from '../../../libraries/storageDisclosure/summary.js'; -import {dynamicDisclosureCollector} from '../../../modules/storageControl.js'; describe('storageDisclosure', () => { let moduleMeta; diff --git a/test/spec/modules/33acrossIdSystem_spec.js b/test/spec/modules/33acrossIdSystem_spec.js index 3a1bf6da2b3..5553d44b9a4 100644 --- a/test/spec/modules/33acrossIdSystem_spec.js +++ b/test/spec/modules/33acrossIdSystem_spec.js @@ -21,6 +21,10 @@ describe('33acrossIdSystem', () => { }); describe('getId', () => { + afterEach(() => { + sinon.restore(); + }); + it('should call endpoint', () => { const completeCallback = sinon.spy(); @@ -96,6 +100,7 @@ describe('33acrossIdSystem', () => { const removeDataFromLocalStorage = sinon.stub(storage, 'removeDataFromLocalStorage'); const setCookie = sinon.stub(storage, 'setCookie'); + sinon.stub(storage, 'cookiesAreEnabled').returns(true); sinon.stub(domainUtils, 'domainOverride').returns('foo.com'); request.respond(200, { @@ -110,10 +115,6 @@ describe('33acrossIdSystem', () => { expect(removeDataFromLocalStorage.calledWithExactly('33acrossIdHm')).to.be.false; expect(setCookie.calledWithExactly('33acrossIdHm', '', sinon.match.string, 'Lax', 'foo.com')).to.be.false; - - removeDataFromLocalStorage.restore(); - setCookie.restore(); - domainUtils.domainOverride.restore(); }); }); @@ -519,6 +520,40 @@ describe('33acrossIdSystem', () => { setDataInLocalStorage.restore(); }); + + it('should not store a publisher-provided hashed email in local storage', () => { + const completeCallback = () => {}; + + const { callback } = thirtyThreeAcrossIdSubmodule.getId({ + params: { + pid: '12345', + storeFpid: false, + hem: '33acrossIdHmValue+' + }, + enabledStorageTypes: [ 'html5' ], + storage: {} + }); + + callback(completeCallback); + + const [request] = server.requests; + + const setDataInLocalStorage = sinon.stub(storage, 'setDataInLocalStorage'); + + request.respond(200, { + 'Content-Type': 'application/json' + }, JSON.stringify({ + succeeded: true, + data: { + envelope: 'foo' + }, + expires: 1645667805067 + })); + + expect(setDataInLocalStorage.calledWithExactly('33acrossIdHm', '33acrossIdHmValue+')).to.be.false; + + setDataInLocalStorage.restore(); + }); }); }); @@ -614,6 +649,7 @@ describe('33acrossIdSystem', () => { const removeDataFromLocalStorage = sinon.stub(storage, 'removeDataFromLocalStorage'); const setCookie = sinon.stub(storage, 'setCookie'); + sinon.stub(storage, 'cookiesAreEnabled').returns(true); sinon.stub(domainUtils, 'domainOverride').returns('foo.com'); request.respond(200, { @@ -630,10 +666,6 @@ describe('33acrossIdSystem', () => { expect(removeDataFromLocalStorage.calledWith(`33acrossId${suffix}`)).to.be.true; expect(setCookie.calledWithExactly(`33acrossId${suffix}`, '', sinon.match.string, 'Lax', 'foo.com')).to.be.true; }); - - removeDataFromLocalStorage.restore(); - setCookie.restore(); - domainUtils.domainOverride.restore(); }); }); @@ -1480,6 +1512,7 @@ describe('33acrossIdSystem', () => { const removeDataFromLocalStorage = sinon.stub(storage, 'removeDataFromLocalStorage'); const setCookie = sinon.stub(storage, 'setCookie'); + const cookiesAreEnabled = sinon.stub(storage, 'cookiesAreEnabled').returns(true); sinon.stub(domainUtils, 'domainOverride').returns('foo.com'); request.respond(200, { @@ -1497,8 +1530,42 @@ describe('33acrossIdSystem', () => { removeDataFromLocalStorage.restore(); setCookie.restore(); + cookiesAreEnabled.restore(); domainUtils.domainOverride.restore(); }); + + it('should not wipe any stored hashed email when first-party ID support is disabled', () => { + const completeCallback = () => {}; + + const { callback } = thirtyThreeAcrossIdSubmodule.getId({ + params: { + pid: '12345', + storeFpid: false + }, + enabledStorageTypes: [ 'html5' ], + storage: {} + }); + + callback(completeCallback); + + const [request] = server.requests; + + const removeDataFromLocalStorage = sinon.stub(storage, 'removeDataFromLocalStorage'); + + request.respond(200, { + 'Content-Type': 'application/json' + }, JSON.stringify({ + succeeded: true, + data: { + // no envelope field + }, + expires: 1645667805067 + })); + + expect(removeDataFromLocalStorage.calledWithExactly('33acrossIdHm')).to.be.false; + + removeDataFromLocalStorage.restore(); + }); }); context('when the server returns an error status code', () => { diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js index b2ca5c622fe..ec2c3a5dc3c 100644 --- a/test/spec/modules/adkernelBidAdapter_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -1,7 +1,6 @@ import {expect} from 'chai'; import {spec} from 'modules/adkernelBidAdapter'; import * as utils from 'src/utils'; -import * as navigatorDnt from 'libraries/dnt/index.js'; import {NATIVE, BANNER, VIDEO} from 'src/mediaTypes'; import {config} from 'src/config'; import {parseDomain} from '../../../src/refererDetection.js'; @@ -342,11 +341,9 @@ describe('Adkernel adapter', function () { } const DEFAULT_BIDDER_REQUEST = buildBidderRequest(); - function buildRequest(bidRequests, bidderRequest = DEFAULT_BIDDER_REQUEST, dnt = true) { - const dntmock = sandbox.stub(navigatorDnt, 'getDNT').callsFake(() => dnt); + function buildRequest(bidRequests, bidderRequest = DEFAULT_BIDDER_REQUEST) { bidderRequest.bids = bidRequests; const pbRequests = spec.buildRequests(bidRequests, bidderRequest); - dntmock.restore(); const rtbRequests = pbRequests.map(r => JSON.parse(r.data)); return [pbRequests, rtbRequests]; } @@ -419,7 +416,6 @@ describe('Adkernel adapter', function () { expect(bidRequest.device).to.have.property('ip', 'caller'); expect(bidRequest.device).to.have.property('ipv6', 'caller'); expect(bidRequest.device).to.have.property('ua', 'caller'); - expect(bidRequest.device).to.have.property('dnt', 1); }); it('should copy FPD to imp.banner', function() { @@ -470,11 +466,6 @@ describe('Adkernel adapter', function () { expect(bidRequest).to.not.have.property('user'); }); - it('should\'t pass dnt if state is unknown', function () { - const [_, bidRequests] = buildRequest([bid1_zone1], DEFAULT_BIDDER_REQUEST, false); - expect(bidRequests[0].device).to.not.have.property('dnt'); - }); - it('should forward default bidder timeout', function() { const [_, bidRequests] = buildRequest([bid1_zone1]); expect(bidRequests[0]).to.have.property('tmax', 3000); diff --git a/test/spec/modules/adoceanBidAdapter_spec.js b/test/spec/modules/adoceanBidAdapter_spec.js index 53a82ec963d..c9e950abeec 100644 --- a/test/spec/modules/adoceanBidAdapter_spec.js +++ b/test/spec/modules/adoceanBidAdapter_spec.js @@ -63,38 +63,6 @@ describe('AdoceanAdapter', function () { expect(spec.isBidRequestValid(videoInscreenBid)).to.equal(true); }); - const videoAdpodBid = { - bidder: 'adocean', - params: { - masterId: 'tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7', - slaveId: 'adoceanmyaozpniqismex', - emitter: 'myao.adocean.pl' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - video: { - context: 'adpod', - playerSize: [300, 250], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - requireExactDuration: false - } - }, - bidId: '30b31c1838de1e', - bidderRequestId: '22edbae2733bf6', - auctionId: '1d1a030790a475', - }; - - it('should return true for adpod video without requireExactDuration', function () { - expect(spec.isBidRequestValid(videoAdpodBid)).to.equal(true); - }); - - it('should return false for adpod video with requireExactDuration', function () { - const invalidBid = Object.assign({}, videoAdpodBid); - invalidBid.mediaTypes.video.requireExactDuration = true; - expect(spec.isBidRequestValid(invalidBid)).to.equal(false); - }); - const videoOutstreamBid = { bidder: 'adocean', params: { @@ -243,41 +211,6 @@ describe('AdoceanAdapter', function () { expect(request.url).to.include('maxdur=60'); expect(request.url).to.include('mindur=10'); }); - - const videoAdpodBidRequests = [ - { - bidder: 'adocean', - params: { - masterId: 'tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7', - slaveId: 'adoceanmyaozpniqismex', - emitter: 'myao.adocean.pl' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - video: { - playerSize: [200, 200], - context: 'adpod', - adPodDurationSec: 300, - durationRangeSec: [15, 30], - requireExactDuration: false - } - }, - bidId: '30b31c1838de1h', - bidderRequestId: '22edbae2733bf6', - auctionId: '1d1a030790a476', - } - ]; - - it('should build correct video adpod request', function () { - const request = spec.buildRequests(videoAdpodBidRequests, bidderRequest)[0]; - expect(request).to.exist; - expect(request.url).to.include('id=' + videoAdpodBidRequests[0].params.masterId); - expect(request.url).to.include('slaves=zpniqismex'); - expect(request.url).to.include('spots=20'); // 300 / 15 = 20 - expect(request.url).to.include('dur=300'); - expect(request.url).to.include('maxdur=30'); - expect(request.url).to.not.include('mindur='); - }); }); describe('interpretResponseBanner', function () { diff --git a/test/spec/modules/adpod_spec.js b/test/spec/modules/adpod_spec.js deleted file mode 100644 index 6e94d98b488..00000000000 --- a/test/spec/modules/adpod_spec.js +++ /dev/null @@ -1,1238 +0,0 @@ -import * as utils from 'src/utils.js'; -import { config } from 'src/config.js'; -import * as videoCache from 'src/videoCache.js'; -import * as auction from 'src/auction.js'; -import { ADPOD } from 'src/mediaTypes.js'; - -import { callPrebidCacheHook, checkAdUnitSetupHook, checkVideoBidSetupHook, adpodSetConfig, sortByPricePerSecond } from 'modules/adpod.js'; - -const expect = require('chai').expect; - -describe('adpod.js', function () { - let logErrorStub; - let logWarnStub; - let logInfoStub; - - describe('callPrebidCacheHook', function () { - let callbackResult; - let clock; - let addBidToAuctionStub; - let doCallbacksIfTimedoutStub; - let storeStub; - let afterBidAddedSpy; - let auctionBids = []; - - const callbackFn = function() { - callbackResult = true; - }; - - const auctionInstance = { - getAuctionStatus: function() { - return auction.AUCTION_IN_PROGRESS; - } - } - - const fakeStoreFn = function(bids, callback) { - const payload = []; - bids.forEach(bid => payload.push({uuid: bid.customCacheKey})); - callback(null, payload); - }; - - beforeEach(function() { - callbackResult = null; - afterBidAddedSpy = sinon.spy(); - storeStub = sinon.stub(videoCache, 'store'); - logWarnStub = sinon.stub(utils, 'logWarn'); - logInfoStub = sinon.stub(utils, 'logInfo'); - addBidToAuctionStub = sinon.stub(auction, 'addBidToAuction').callsFake(function (auctionInstance, bid) { - auctionBids.push(bid); - }); - clock = sinon.useFakeTimers(); - config.setConfig({ - cache: { - url: 'https://test.cache.url/endpoint' - } - }); - }); - - afterEach(function() { - storeStub.restore(); - logWarnStub.restore(); - logInfoStub.restore(); - addBidToAuctionStub.restore(); - clock.restore(); - config.resetConfig(); - auctionBids = []; - }) - - it('should redirect back to the original function if bid is not an adpod video', function () { - const bid = { - adId: 'testAdId_123', - mediaType: 'video' - }; - - const videoMT = { - context: 'outstream' - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bid, function () {}, videoMT); - expect(callbackResult).to.equal(true); - }); - - it('should immediately add the adpod bid to auction if adpod.deferCaching in config is true', function() { - config.setConfig({ - adpod: { - deferCaching: true, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'adId01277', - auctionId: 'no_defer_123', - mediaType: 'video', - cpm: 5, - pbMg: '5.00', - adserverTargeting: { - hb_pb: '5.00' - }, - meta: { - adServerCatId: 'test' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const bidResponse2 = { - adId: 'adId46547', - auctionId: 'no_defer_123', - mediaType: 'video', - cpm: 12, - pbMg: '12.00', - adserverTargeting: { - hb_pb: '12.00' - }, - meta: { - adServerCatId: 'value' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 300, - durationRangeSec: [15, 30, 45], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - // check if bid adsereverTargeting is setup - expect(callbackResult).to.be.null; - expect(storeStub.called).to.equal(false); - expect(afterBidAddedSpy.calledTwice).to.equal(true); - expect(auctionBids.length).to.equal(2); - expect(auctionBids[0].adId).to.equal(bidResponse1.adId); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^5\.00_test_15s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('5.00_test_15s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - expect(auctionBids[1].adId).to.equal(bidResponse2.adId); - expect(auctionBids[1].customCacheKey).to.exist.and.to.match(/^12\.00_value_15s_.*/); - expect(auctionBids[1].adserverTargeting.hb_pb_cat_dur).to.equal('12.00_value_15s'); - expect(auctionBids[1].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[1].adserverTargeting.hb_cache_id).to.equal(auctionBids[0].adserverTargeting.hb_cache_id); - expect(auctionBids[1].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id); - }); - - it('should send prebid cache call once bid queue is full', function () { - storeStub.callsFake(fakeStoreFn); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'adId123', - auctionId: 'full_abc123', - mediaType: 'video', - cpm: 10, - pbMg: '10.00', - adserverTargeting: { - hb_pb: '10.00' - }, - meta: { - adServerCatId: 'airline' - }, - video: { - context: ADPOD, - durationSeconds: 20, - durationBucket: 30 - } - }; - const bidResponse2 = { - adId: 'adId234', - auctionId: 'full_abc123', - mediaType: 'video', - cpm: 15, - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00' - }, - meta: { - adServerCatId: 'airline' - }, - video: { - context: ADPOD, - durationSeconds: 25, - durationBucket: 30 - } - }; - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 120, - durationRangeSec: [15, 30], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledTwice).to.equal(true); - expect(auctionBids.length).to.equal(2); - expect(auctionBids[0].adId).to.equal('adId123'); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^10\.00_airline_30s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('10.00_airline_30s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - expect(auctionBids[1].adId).to.equal('adId234'); - expect(auctionBids[1].customCacheKey).to.exist.and.to.match(/^15\.00_airline_30s_.*/); - expect(auctionBids[1].adserverTargeting.hb_pb_cat_dur).to.equal('15.00_airline_30s'); - expect(auctionBids[1].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[1].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - }); - - it('should send prebid cache call after set period of time (even if queue is not full)', function () { - storeStub.callsFake(fakeStoreFn); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - bidQueueTimeDelay: 30, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse = { - adId: 'adId234', - auctionId: 'timer_abc234', - mediaType: 'video', - cpm: 15, - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00' - }, - meta: { - adServerCatId: 'airline' - }, - video: { - context: ADPOD, - durationSeconds: 30, - durationBucket: 30 - } - }; - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 120, - durationRangeSec: [15, 30], - requireExactDuration: true - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse, afterBidAddedSpy, videoMT); - clock.tick(31); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledOnce).to.equal(true); - expect(auctionBids.length).to.equal(1); - expect(auctionBids[0].adId).to.equal('adId234'); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^15\.00_airline_30s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('15.00_airline_30s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - }); - - it('should execute multiple prebid cache calls when number of bids exceeds queue size', function () { - storeStub.callsFake(fakeStoreFn); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - bidQueueTimeDelay: 30, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'multi_ad1', - auctionId: 'multi_call_abc345', - mediaType: 'video', - cpm: 15, - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00' - }, - meta: { - adServerCatId: 'airline' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - const bidResponse2 = { - adId: 'multi_ad2', - auctionId: 'multi_call_abc345', - mediaType: 'video', - cpm: 15, - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00' - }, - meta: { - adServerCatId: 'news' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - const bidResponse3 = { - adId: 'multi_ad3', - auctionId: 'multi_call_abc345', - mediaType: 'video', - cpm: 10, - pbMg: '10.00', - adserverTargeting: { - hb_pb: '10.00' - }, - meta: { - adServerCatId: 'sports' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 45, - durationRangeSec: [15, 30], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse3, afterBidAddedSpy, videoMT); - clock.next(); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledThrice).to.equal(true); - expect(storeStub.calledTwice).to.equal(true); - expect(auctionBids.length).to.equal(3); - expect(auctionBids[0].adId).to.equal('multi_ad1'); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^15\.00_airline_15s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('15.00_airline_15s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - expect(auctionBids[1].adId).to.equal('multi_ad2'); - expect(auctionBids[1].customCacheKey).to.exist.and.to.match(/^15\.00_news_15s_.*/); - expect(auctionBids[1].adserverTargeting.hb_pb_cat_dur).to.equal('15.00_news_15s'); - expect(auctionBids[1].adserverTargeting.hb_cache_id).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id); - expect(auctionBids[1].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - expect(auctionBids[2].adId).to.equal('multi_ad3'); - expect(auctionBids[2].customCacheKey).to.exist.and.to.match(/^10\.00_sports_15s_.*/); - expect(auctionBids[2].adserverTargeting.hb_pb_cat_dur).to.equal('10.00_sports_15s'); - expect(auctionBids[2].adserverTargeting.hb_cache_id).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id); - expect(auctionBids[2].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - }); - - it('should cache the bids with a shortened custom key when adpod.brandCategoryExclusion is false', function() { - storeStub.callsFake(fakeStoreFn); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - bidQueueTimeDelay: 30, - deferCaching: false, - brandCategoryExclusion: false - } - }); - - const bidResponse1 = { - adId: 'nocat_ad1', - auctionId: 'no_category_abc345', - mediaType: 'video', - cpm: 10, - pbMg: '10.00', - adserverTargeting: { - hb_pb: '10.00' - }, - meta: { - adServerCatId: undefined - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - const bidResponse2 = { - adId: 'nocat_ad2', - auctionId: 'no_category_abc345', - mediaType: 'video', - cpm: 15, - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00' - }, - meta: { - adServerCatId: undefined - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 45, - durationRangeSec: [15, 30], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledTwice).to.equal(true); - expect(storeStub.calledOnce).to.equal(true); - expect(auctionBids.length).to.equal(2); - expect(auctionBids[0].adId).to.equal('nocat_ad1'); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^10\.00_15s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('10.00_15s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - expect(auctionBids[1].adId).to.equal('nocat_ad2'); - expect(auctionBids[1].customCacheKey).to.exist.and.to.match(/^15\.00_15s_.*/); - expect(auctionBids[1].adserverTargeting.hb_pb_cat_dur).to.equal('15.00_15s'); - expect(auctionBids[1].adserverTargeting.hb_cache_id).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id); - expect(auctionBids[1].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - }); - - it('should not add bid to auction when config adpod.brandCategoryExclusion is true but bid is missing adServerCatId', function() { - storeStub.callsFake(fakeStoreFn); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - bidQueueTimeDelay: 30, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'missingCat_ad1', - auctionId: 'missing_category_abc345', - mediaType: 'video', - cpm: 10, - meta: { - adServerCatId: undefined - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 45, - durationRangeSec: [15, 30], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledOnce).to.equal(true); - expect(storeStub.called).to.equal(false); - expect(logWarnStub.calledOnce).to.equal(true); - expect(auctionBids.length).to.equal(0); - }); - - it('should not add bid to auction when Prebid Cache detects an existing key', function () { - storeStub.callsFake(function(bids, callback) { - const payload = []; - bids.forEach(bid => payload.push({uuid: bid.customCacheKey})); - - // fake a duplicate bid response from PBC (sets an empty string for the uuid) - payload[1].uuid = ''; - callback(null, payload); - }); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'dup_ad_1', - auctionId: 'duplicate_def123', - mediaType: 'video', - cpm: 5, - pbMg: '5.00', - adserverTargeting: { - hb_pb: '5.00' - }, - meta: { - adServerCatId: 'tech' - }, - video: { - context: ADPOD, - durationSeconds: 45, - durationBucket: 45 - } - }; - const bidResponse2 = { - adId: 'dup_ad_2', - auctionId: 'duplicate_def123', - mediaType: 'video', - cpm: 5, - pbMg: '5.00', - adserverTargeting: { - hb_pb: '5.00' - }, - meta: { - adServerCatId: 'tech' - }, - video: { - context: ADPOD, - durationSeconds: 45, - durationBucket: 45 - } - }; - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 120, - durationRangeSec: [15, 30, 45], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledTwice).to.equal(true); - expect(storeStub.calledOnce).to.equal(true); - expect(logInfoStub.calledOnce).to.equal(true); - expect(auctionBids.length).to.equal(1); - expect(auctionBids[0].adId).to.equal('dup_ad_1'); - expect(auctionBids[0].customCacheKey).to.exist.and.to.match(/^5\.00_tech_45s_.*/); - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('5.00_tech_45s'); - expect(auctionBids[0].adserverTargeting.hb_cache_id).to.exist; - expect(auctionBids[0].videoCacheKey).to.exist.and.to.equal(auctionBids[0].adserverTargeting.hb_cache_id) - }); - - it('should not add bids to auction if PBC returns an error', function() { - storeStub.callsFake(function(bids, callback) { - const payload = []; - const errmsg = 'invalid json'; - - callback(errmsg, payload); - }); - - config.setConfig({ - adpod: { - bidQueueSizeLimit: 2, - deferCaching: false, - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'err_ad_1', - auctionId: 'error_xyz123', - mediaType: 'video', - cpm: 5, - meta: { - adServerCatId: 'tech' - }, - video: { - context: ADPOD, - durationSeconds: 30, - durationBucket: 30 - } - }; - const bidResponse2 = { - adId: 'err_ad_2', - auctionId: 'error_xyz123', - mediaType: 'video', - cpm: 5, - meta: { - adServerCatId: 'tech' - }, - video: { - context: ADPOD, - durationSeconds: 30, - durationBucket: 30 - } - }; - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 120, - durationRangeSec: [15, 30, 45], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - expect(logWarnStub.calledOnce).to.equal(true); - expect(auctionBids.length).to.equal(0); - }); - - it('should use bid.adserverTargeting.hb_pb when custom price granularity is configured', function() { - storeStub.callsFake(fakeStoreFn); - - const customConfigObject = { - 'buckets': [{ - 'precision': 2, // default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12 - 'max': 5, - 'increment': 0.01 // from $0 to $5, 1-cent increments - }, - { - 'precision': 2, - 'max': 8, - 'increment': 0.05 // from $5 to $8, round down to the previous 5-cent increment - }, - { - 'precision': 2, - 'max': 40, - 'increment': 0.5 // from $8 to $40, round down to the previous 50-cent increment - }] - }; - config.setConfig({ - priceGranularity: customConfigObject, - adpod: { - brandCategoryExclusion: true - } - }); - - const bidResponse1 = { - adId: 'cat_ad1', - auctionId: 'test_category_abc345', - mediaType: 'video', - cpm: 15, - pbAg: '15.00', - pbCg: '15.00', - pbDg: '15.00', - pbHg: '15.00', - pbLg: '5.00', - pbMg: '15.00', - adserverTargeting: { - hb_pb: '15.00', - }, - meta: { - adServerCatId: 'test' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 45, - durationRangeSec: [15, 30], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - - expect(callbackResult).to.be.null; - expect(afterBidAddedSpy.calledOnce).to.equal(true); - expect(storeStub.called).to.equal(false); - expect(auctionBids.length).to.equal(1); - }); - - it('should set deal tier in place of cpm when prioritzeDeals is true', function() { - config.setConfig({ - adpod: { - deferCaching: true, - brandCategoryExclusion: true, - prioritizeDeals: true, - dealTier: { - 'appnexus': { - 'prefix': 'tier', - 'minDealTier': 5 - } - } - } - }); - - const bidResponse1 = { - adId: 'adId01277', - auctionId: 'no_defer_123', - mediaType: 'video', - bidderCode: 'appnexus', - cpm: 5, - pbMg: '5.00', - adserverTargeting: { - hb_pb: '5.00' - }, - meta: { - adServerCatId: 'test' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15, - dealTier: 7 - } - }; - - const bidResponse2 = { - adId: 'adId46547', - auctionId: 'no_defer_123', - mediaType: 'video', - bidderCode: 'appnexus', - cpm: 12, - pbMg: '12.00', - adserverTargeting: { - hb_pb: '12.00' - }, - meta: { - adServerCatId: 'value' - }, - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - } - }; - - const videoMT = { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 300, - durationRangeSec: [15, 30, 45], - requireExactDuration: false - }; - - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse1, afterBidAddedSpy, videoMT); - callPrebidCacheHook(callbackFn, auctionInstance, bidResponse2, afterBidAddedSpy, videoMT); - - expect(auctionBids[0].adserverTargeting.hb_pb_cat_dur).to.equal('tier7_test_15s'); - expect(auctionBids[1].adserverTargeting.hb_pb_cat_dur).to.equal('12.00_value_15s'); - }) - }); - - describe('checkAdUnitSetupHook', function () { - let results; - const callbackFn = function (adUnits) { - results = adUnits; - }; - - beforeEach(function () { - logWarnStub = sinon.stub(utils, 'logWarn'); - results = null; - }); - - afterEach(function() { - utils.logWarn.restore(); - }); - - it('removes an incorrectly setup adpod adunit - required fields are missing', function() { - const adUnits = [{ - code: 'test1', - mediaTypes: { - video: { - context: ADPOD - } - } - }, { - code: 'test2', - mediaTypes: { - video: { - context: 'instream' - } - } - }]; - - checkAdUnitSetupHook(callbackFn, adUnits); - - expect(results).to.deep.equal([{ - code: 'test2', - mediaTypes: { - video: { - context: 'instream' - } - } - }]); - expect(logWarnStub.calledOnce).to.equal(true); - }); - - it('removes an incorrectly setup adpod adunit - required fields are using invalid values', function() { - const adUnits = [{ - code: 'test1', - mediaTypes: { - video: { - context: ADPOD, - durationRangeSec: [-5, 15, 30, 45], - adPodDurationSec: 300 - } - } - }]; - - checkAdUnitSetupHook(callbackFn, adUnits); - - expect(results).to.deep.equal([]); - expect(logWarnStub.calledOnce).to.equal(true); - - adUnits[0].mediaTypes.video.durationRangeSec = [15, 30, 45]; - adUnits[0].mediaTypes.video.adPodDurationSec = 0; - - checkAdUnitSetupHook(callbackFn, adUnits); - - expect(results).to.deep.equal([]); - expect(logWarnStub.calledTwice).to.equal(true); - }); - - it('removes an incorrectly setup adpod adunit - attempting to use multi-format adUnit', function() { - const adUnits = [{ - code: 'multi_test1', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - }, - video: { - context: 'adpod', - playerSize: [[300, 250]], - durationRangeSec: [15, 30, 45], - adPodDurationSec: 300 - } - } - }]; - - checkAdUnitSetupHook(callbackFn, adUnits); - - expect(results).to.deep.equal([]); - expect(logWarnStub.calledOnce).to.equal(true); - }); - - it('accepts mixed set of adunits', function() { - const adUnits = [{ - code: 'test3', - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[300, 300]], - adPodDurationSec: 360, - durationRangeSec: [15, 30, 45], - requireExactDuration: true - } - } - }, { - code: 'test4', - mediaTypes: { - banner: { - sizes: [[300, 250]] - } - } - }]; - - checkAdUnitSetupHook(callbackFn, adUnits); - - expect(results).to.deep.equal(adUnits); - expect(logWarnStub.called).to.equal(false); - }); - }); - - describe('checkVideoBidSetupHook', function () { - let callbackResult; - let bailResult; - const callbackFn = { - call: function(context, bid) { - callbackResult = bid; - }, - bail: function(result) { - bailResult = result; - } - } - const adpodTestBid = { - video: { - context: ADPOD, - durationSeconds: 15, - durationBucket: 15 - }, - meta: { - primaryCatId: 'testCategory_123' - }, - vastXml: 'test XML here' - }; - const adUnitNoExact = { - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[300, 400]], - durationRangeSec: [15, 45], - requireExactDuration: false, - adPodDurationSec: 300 - } - } - }; - const adUnitWithExact = { - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[300, 400]], - durationRangeSec: [15, 30, 45, 60], - requireExactDuration: true, - adPodDurationSec: 300 - } - } - }; - - beforeEach(function() { - callbackResult = null; - bailResult = null; - config.setConfig({ - cache: { - url: 'https://test.cache.url/endpoint' - }, - adpod: { - brandCategoryExclusion: true - } - }); - logWarnStub = sinon.stub(utils, 'logWarn'); - logErrorStub = sinon.stub(utils, 'logError'); - }); - - afterEach(function() { - config.resetConfig(); - logWarnStub.restore(); - logErrorStub.restore(); - }) - - it('redirects to original function for non-adpod type video bids', function() { - const bannerTestBid = { - mediaType: 'video' - }; - checkVideoBidSetupHook(callbackFn, bannerTestBid, {}, {}, 'instream'); - expect(callbackResult).to.deep.equal(bannerTestBid); - expect(bailResult).to.be.null; - expect(logErrorStub.called).to.equal(false); - }); - - it('returns true when adpod bid is properly setup', function() { - config.setConfig({ - cache: { - url: 'https://test.cache.url/endpoint' - }, - adpod: { - brandCategoryExclusion: false - } - }); - - const goodBid = utils.deepClone(adpodTestBid); - goodBid.meta.primaryCatId = undefined; - checkVideoBidSetupHook(callbackFn, goodBid, adUnitNoExact, adUnitNoExact.mediaTypes.video, ADPOD); - expect(callbackResult).to.be.null; - expect(bailResult).to.equal(true); - expect(logErrorStub.called).to.equal(false); - }); - - it('returns true when adpod bid is missing iab category while brandCategoryExclusion in config is false', function() { - const goodBid = utils.deepClone(adpodTestBid); - checkVideoBidSetupHook(callbackFn, goodBid, adUnitNoExact, adUnitNoExact.mediaTypes.video, ADPOD); - expect(callbackResult).to.be.null; - expect(bailResult).to.equal(true); - expect(logErrorStub.called).to.equal(false); - }); - - it('returns false when a required property from an adpod bid is missing', function() { - function testInvalidAdpodBid(badTestBid, shouldErrorBeLogged) { - checkVideoBidSetupHook(callbackFn, badTestBid, adUnitNoExact, adUnitNoExact.mediaTypes.video, ADPOD); - expect(callbackResult).to.be.null; - expect(bailResult).to.equal(false); - expect(logErrorStub.called).to.equal(shouldErrorBeLogged); - } - - const noCatBid = utils.deepClone(adpodTestBid); - noCatBid.meta.primaryCatId = undefined; - testInvalidAdpodBid(noCatBid, false); - - const noContextBid = utils.deepClone(adpodTestBid); - delete noContextBid.video.context; - testInvalidAdpodBid(noContextBid, false); - - const wrongContextBid = utils.deepClone(adpodTestBid); - wrongContextBid.video.context = 'instream'; - testInvalidAdpodBid(wrongContextBid, false); - - const noDurationBid = utils.deepClone(adpodTestBid); - delete noDurationBid.video.durationSeconds; - testInvalidAdpodBid(noDurationBid, false); - - config.resetConfig(); - const noCacheUrlBid = utils.deepClone(adpodTestBid); - testInvalidAdpodBid(noCacheUrlBid, true); - }); - - describe('checkBidDuration', function() { - const basicBid = { - video: { - context: ADPOD, - durationSeconds: 30 - }, - meta: { - primaryCatId: 'testCategory_123' - }, - vastXml: '' - }; - - it('when requireExactDuration is true', function() { - const goodBid = utils.deepClone(basicBid); - checkVideoBidSetupHook(callbackFn, goodBid, adUnitWithExact, adUnitWithExact.mediaTypes.video, ADPOD); - - expect(callbackResult).to.be.null; - expect(goodBid.video.durationBucket).to.equal(30); - expect(bailResult).to.equal(true); - expect(logWarnStub.called).to.equal(false); - - const badBid = utils.deepClone(basicBid); - badBid.video.durationSeconds = 14; - checkVideoBidSetupHook(callbackFn, badBid, adUnitWithExact, adUnitWithExact.mediaTypes.video, ADPOD); - - expect(callbackResult).to.be.null; - expect(badBid.video.durationBucket).to.be.undefined; - expect(bailResult).to.equal(false); - expect(logWarnStub.calledOnce).to.equal(true); - }); - - it('when requireExactDuration is false and bids are bucketed properly', function() { - function testRoundingForGoodBId(bid, bucketValue) { - checkVideoBidSetupHook(callbackFn, bid, adUnitNoExact, adUnitNoExact.mediaTypes.video, ADPOD); - expect(callbackResult).to.be.null; - expect(bid.video.durationBucket).to.equal(bucketValue); - expect(bailResult).to.equal(true); - expect(logWarnStub.called).to.equal(false); - } - - const goodBid45 = utils.deepClone(basicBid); - goodBid45.video.durationSeconds = 45; - testRoundingForGoodBId(goodBid45, 45); - - const goodBid30 = utils.deepClone(basicBid); - goodBid30.video.durationSeconds = 30; - testRoundingForGoodBId(goodBid30, 45); - - const goodBid10 = utils.deepClone(basicBid); - goodBid10.video.durationSeconds = 10; - testRoundingForGoodBId(goodBid10, 15); - - const goodBid16 = utils.deepClone(basicBid); - goodBid16.video.durationSeconds = 16; - testRoundingForGoodBId(goodBid16, 15); - - const goodBid47 = utils.deepClone(basicBid); - goodBid47.video.durationSeconds = 47; - testRoundingForGoodBId(goodBid47, 45); - }); - - it('when requireExactDuration is false and bid duration exceeds listed buckets', function() { - function testRoundingForBadBid(bid) { - checkVideoBidSetupHook(callbackFn, bid, adUnitNoExact, adUnitNoExact.mediaTypes.video, ADPOD); - expect(callbackResult).to.be.null; - expect(bid.video.durationBucket).to.be.undefined; - expect(bailResult).to.equal(false); - expect(logWarnStub.called).to.equal(true); - } - - const badBid100 = utils.deepClone(basicBid); - badBid100.video.durationSeconds = 100; - testRoundingForBadBid(badBid100); - - const badBid48 = utils.deepClone(basicBid); - badBid48.video.durationSeconds = 48; - testRoundingForBadBid(badBid48); - }); - }); - }); - - describe('adpodSetConfig', function () { - let logWarnStub; - beforeEach(function() { - logWarnStub = sinon.stub(utils, 'logWarn'); - }); - - afterEach(function () { - logWarnStub.restore(); - }); - - it('should log a warning when values other than numbers are used in setConfig', function() { - adpodSetConfig({ - bidQueueSizeLimit: '2', - bidQueueTimeDelay: '50' - }); - expect(logWarnStub.calledTwice).to.equal(true); - }); - - it('should log a warning when numbers less than or equal to zero are used in setConfig', function() { - adpodSetConfig({ - bidQueueSizeLimit: 0, - bidQueueTimeDelay: -2 - }); - expect(logWarnStub.calledTwice).to.equal(true); - }); - - it('should not log any warning when using a valid config', function() { - adpodSetConfig({ - bidQueueSizeLimit: 10 - }); - expect(logWarnStub.called).to.equal(false); - - adpodSetConfig({ - bidQueueTimeDelay: 100, - bidQueueSizeLimit: 20 - }); - expect(logWarnStub.called).to.equal(false); - }) - }); - - describe('adpod utils', function() { - it('should sort bids array', function() { - const bids = [{ - cpm: 10.12345, - adserverTargeting: { - hb_pb: '10.00', - }, - video: { - durationBucket: 15 - } - }, { - cpm: 15, - adserverTargeting: { - hb_pb: '15.00', - }, - video: { - durationBucket: 15 - } - }, { - cpm: 15.00, - adserverTargeting: { - hb_pb: '15.00', - }, - video: { - durationBucket: 30 - } - }, { - cpm: 5.45, - adserverTargeting: { - hb_pb: '5.00', - }, - video: { - durationBucket: 5 - } - }, { - cpm: 20.1234567, - adserverTargeting: { - hb_pb: '20.10', - }, - video: { - durationBucket: 60 - } - }] - bids.sort(sortByPricePerSecond); - const sortedBids = [{ - cpm: 15, - adserverTargeting: { - hb_pb: '15.00', - }, - video: { - durationBucket: 15 - } - }, { - cpm: 5.45, - adserverTargeting: { - hb_pb: '5.00', - }, - video: { - durationBucket: 5 - } - }, { - cpm: 10.12345, - adserverTargeting: { - hb_pb: '10.00', - }, - video: { - durationBucket: 15 - } - }, { - cpm: 15.00, - adserverTargeting: { - hb_pb: '15.00', - }, - video: { - durationBucket: 30 - } - }, { - cpm: 20.1234567, - adserverTargeting: { - hb_pb: '20.10', - }, - video: { - durationBucket: 60 - } - }] - expect(bids).to.include.deep.ordered.members(sortedBids); - }); - }) -}); diff --git a/test/spec/modules/adtelligentBidAdapter_spec.js b/test/spec/modules/adtelligentBidAdapter_spec.js index bcce942f47f..eed27cdd57b 100644 --- a/test/spec/modules/adtelligentBidAdapter_spec.js +++ b/test/spec/modules/adtelligentBidAdapter_spec.js @@ -52,24 +52,6 @@ const VIDEO_REQUEST = { 'ortb2Imp': { 'ext': { 'gpid': '12345/adunit-code' } }, }; -const ADPOD_REQUEST = { - 'bidder': 'adtelligent', - 'mediaTypes': { - 'video': { - 'context': 'adpod', - 'playerSize': [[640, 480]], - 'anyField': 10 - } - }, - 'params': { - 'aid': 12345 - }, - 'bidderRequestId': '7101db09af0db2', - 'auctionId': '2e41f65424c87c', - 'adUnitCode': 'adunit-code', - 'bidId': '2e41f65424c87c' -}; - const SERVER_VIDEO_RESPONSE = { 'source': { 'aid': 12345, 'pubId': 54321 }, 'bids': [{ @@ -310,13 +292,6 @@ describe('adtelligentBidAdapter', () => { expect(displayRequest.every(comparator)).to.be.true; expect(videoAndDisplayRequests.every(comparator)).to.be.true; }); - it('forms correct ADPOD request', () => { - const pbBidReqData = spec.buildRequests([ADPOD_REQUEST], DEFAULT_ADATPER_REQ)[0].data; - const impRequest = pbBidReqData.BidRequests[0] - expect(impRequest.AdType).to.be.equal('video'); - expect(impRequest.Adpod).to.be.a('object'); - expect(impRequest.Adpod.anyField).to.be.equal(10); - }) it('sends correct video bid parameters', () => { const data = videoRequest[0].data; @@ -454,12 +429,6 @@ describe('adtelligentBidAdapter', () => { nobidServerResponseCheck(); }); - - it('forms correct ADPOD response', () => { - const videoBids = spec.interpretResponse({ body: SERVER_VIDEO_RESPONSE }, { adapterRequest: { bids: [ADPOD_REQUEST] } }); - expect(videoBids[0].video.durationSeconds).to.be.equal(30); - expect(videoBids[0].video.context).to.be.equal('adpod'); - }) describe('outstream setup', () => { const videoBids = spec.interpretResponse({ body: SERVER_OUSTREAM_VIDEO_RESPONSE }, { adapterRequest: outstreamVideoBidderRequest }); it('should return renderer with expected outstream params config', () => { diff --git a/test/spec/modules/adtrgtmeBidAdapter_spec.js b/test/spec/modules/adtrgtmeBidAdapter_spec.js index 702086c48a2..960028a379c 100644 --- a/test/spec/modules/adtrgtmeBidAdapter_spec.js +++ b/test/spec/modules/adtrgtmeBidAdapter_spec.js @@ -562,7 +562,7 @@ describe('Adtrgtme Bid Adapter:', () => { }); expect(data.device).to.deep.equal({ - dnt: 0, + dnt: 0, // DNT deprecated by W3C; Prebid no longer supports DNT ua: navigator.userAgent, ip: undefined }); diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index f4a00bfb264..826cc9e76ad 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -536,185 +536,6 @@ describe('AppNexusAdapter', function () { playback_method: 2 }); }); - - it('should duplicate adpod placements into batches and set correct maxduration', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - - // 300 / 15 = 20 total - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(5); - - expect(payload1.tags[0]).to.deep.equal(payload1.tags[1]); - expect(payload1.tags[0].video.maxduration).to.equal(30); - - expect(payload2.tags[0]).to.deep.equal(payload1.tags[1]); - expect(payload2.tags[0].video.maxduration).to.equal(30); - }); - - it('should round down adpod placements when numbers are uneven', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 123, - durationRangeSec: [45], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - expect(payload.tags.length).to.equal(2); - }); - - it('should duplicate adpod placements when requireExactDuration is set', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - requireExactDuration: true, - } - } - } - ); - - // 20 total placements with 15 max impressions = 2 requests - const request = spec.buildRequests([bidRequest]); - expect(request.length).to.equal(2); - - // 20 spread over 2 requests = 15 in first request, 5 in second - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(5); - - // 10 placements should have max/min at 15 - // 10 placemenst should have max/min at 30 - const payload1tagsWith15 = payload1.tags.filter(tag => tag.video.maxduration === 15); - const payload1tagsWith30 = payload1.tags.filter(tag => tag.video.maxduration === 30); - expect(payload1tagsWith15.length).to.equal(10); - expect(payload1tagsWith30.length).to.equal(5); - - // 5 placemenst with min/max at 30 were in the first request - // so 5 remaining should be in the second - const payload2tagsWith30 = payload2.tags.filter(tag => tag.video.maxduration === 30); - expect(payload2tagsWith30.length).to.equal(5); - }); - - it('should set durations for placements when requireExactDuration is set and numbers are uneven', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 105, - durationRangeSec: [15, 30, 60], - requireExactDuration: true, - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - expect(payload.tags.length).to.equal(7); - - const tagsWith15 = payload.tags.filter(tag => tag.video.maxduration === 15); - const tagsWith30 = payload.tags.filter(tag => tag.video.maxduration === 30); - const tagsWith60 = payload.tags.filter(tag => tag.video.maxduration === 60); - expect(tagsWith15.length).to.equal(3); - expect(tagsWith30.length).to.equal(3); - expect(tagsWith60.length).to.equal(1); - }); - - it('should break adpod request into batches', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 225, - durationRangeSec: [5], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - const payload3 = JSON.parse(request[2].data); - - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(15); - expect(payload3.tags.length).to.equal(15); - }); - - it('should contain hb_source value for adpod', function () { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - } - } - } - ); - const request = spec.buildRequests([bidRequest])[0]; - const payload = JSON.parse(request.data); - expect(payload.tags[0].hb_source).to.deep.equal(7); - }); } // VIDEO it('sends bid request to ENDPOINT via POST', function () { @@ -817,21 +638,6 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].hb_source).to.deep.equal(1); }); - it('adds brand_category_exclusion to request when set', function () { - const bidRequest = Object.assign({}, bidRequests[0]); - sinon - .stub(config, 'getConfig') - .withArgs('adpod.brandCategoryExclusion') - .returns(true); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - - expect(payload.brand_category_uniqueness).to.equal(true); - - config.getConfig.restore(); - }); - it('adds auction level keywords and ortb2 keywords to request when set', function () { const bidRequest = Object.assign({}, bidRequests[0]); sinon @@ -2024,46 +1830,6 @@ describe('AppNexusAdapter', function () { expect(result[0]).to.have.property('vastImpUrl'); expect(result[0]).to.have.property('mediaType', 'video'); }); - - it('handles adpod responses', function () { - const response = { - 'tags': [{ - 'uuid': '84ab500420319d', - 'ads': [{ - 'ad_type': 'video', - 'brand_category_id': 10, - 'cpm': 0.500000, - 'notify_url': 'imptracker.com', - 'rtb': { - 'video': { - 'asset_url': 'https://sample.vastURL.com/here/adpod', - 'duration_ms': 30000, - } - }, - 'viewability': { - 'config': '' - } - }] - }] - }; - - const bidderRequest = { - bids: [{ - bidId: '84ab500420319d', - adUnitCode: 'code', - mediaTypes: { - video: { - context: 'adpod' - } - } - }] - }; - - const result = spec.interpretResponse({ body: response }, { bidderRequest }); - expect(result[0]).to.have.property('vastUrl'); - expect(result[0].video.context).to.equal('adpod'); - expect(result[0].video.durationSeconds).to.equal(30); - }); } if (FEATURES.NATIVE) { @@ -2377,33 +2143,6 @@ describe('AppNexusAdapter', function () { bidderRequest.bids[0].renderer.options ); }); - - it('should add deal_priority and deal_code', function () { - const responseWithDeal = deepClone(response); - responseWithDeal.tags[0].ads[0].ad_type = 'video'; - responseWithDeal.tags[0].ads[0].deal_priority = 5; - responseWithDeal.tags[0].ads[0].deal_code = '123'; - responseWithDeal.tags[0].ads[0].rtb.video = { - duration_ms: 1500, - player_width: 640, - player_height: 340, - }; - - const bidderRequest = { - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code', - mediaTypes: { - video: { - context: 'adpod' - } - } - }] - } - const result = spec.interpretResponse({ body: responseWithDeal }, { bidderRequest }); - expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']); - expect(result[0].video.dealTier).to.equal(5); - }); } it('should add advertiser id', function () { diff --git a/test/spec/modules/categoryTranslation_spec.js b/test/spec/modules/categoryTranslation_spec.js deleted file mode 100644 index 3aeca0fbf75..00000000000 --- a/test/spec/modules/categoryTranslation_spec.js +++ /dev/null @@ -1,109 +0,0 @@ -import { getAdserverCategoryHook, initTranslation, storage } from 'modules/categoryTranslation.js'; -import { config } from 'src/config.js'; -import * as utils from 'src/utils.js'; -import { expect } from 'chai'; -import {server} from '../../mocks/xhr.js'; - -describe('category translation', function () { - let getLocalStorageStub; - - beforeEach(function () { - getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); - }); - - afterEach(function() { - getLocalStorageStub.restore(); - config.resetConfig(); - }); - - it('should translate iab category to adserver category', function () { - config.setConfig({ - 'adpod': { - 'brandCategoryExclusion': true - } - }); - getLocalStorageStub.returns(JSON.stringify({ - 'mapping': { - 'iab-1': { - 'id': 1, - 'name': 'sample' - } - } - })); - const bid = { - meta: { - primaryCatId: 'iab-1' - } - } - getAdserverCategoryHook(sinon.spy(), 'code', bid); - expect(bid.meta.adServerCatId).to.equal(1); - }); - - it('should set adserverCatId to undefined if not found in mapping file', function() { - config.setConfig({ - 'adpod': { - 'brandCategoryExclusion': true - } - }); - getLocalStorageStub.returns(JSON.stringify({ - 'mapping': { - 'iab-1': { - 'id': 1, - 'name': 'sample' - } - } - })); - const bid = { - meta: { - primaryCatId: 'iab-2' - } - } - getAdserverCategoryHook(sinon.spy(), 'code', bid); - expect(bid.meta.adServerCatId).to.equal(undefined); - }); - - it('should not make ajax call to update mapping file if data found in localstorage and is not expired', function () { - const clock = sinon.useFakeTimers(utils.timestamp()); - getLocalStorageStub.returns(JSON.stringify({ - lastUpdated: utils.timestamp(), - mapping: { - 'iab-1': '1' - } - })); - initTranslation(); - expect(server.requests.length).to.equal(0); - clock.restore(); - }); - - it('should make ajax call to update mapping file if data found in localstorage is expired', function () { - const clock = sinon.useFakeTimers(utils.timestamp()); - getLocalStorageStub.returns(JSON.stringify({ - lastUpdated: utils.timestamp() - 2 * 24 * 60 * 60 * 1000, - mapping: { - 'iab-1': '1' - } - })); - initTranslation(); - expect(server.requests.length).to.equal(1); - clock.restore(); - }); - - it('should use default mapping file if publisher has not defined in config', function () { - getLocalStorageStub.returns(null); - initTranslation('http://sample.com', 'somekey'); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('http://sample.com/'); - }); - - it('should use publisher defined mapping file', function () { - config.setConfig({ - 'brandCategoryTranslation': { - 'translationFile': 'http://sample.com' - } - }); - getLocalStorageStub.returns(null); - initTranslation('http://sample.com', 'somekey'); - expect(server.requests.length).to.equal(2); - expect(server.requests[0].url).to.equal('http://sample.com/'); - }); -}); diff --git a/test/spec/modules/ccxBidAdapter_spec.js b/test/spec/modules/ccxBidAdapter_spec.js index 83865c72907..e512f12415f 100644 --- a/test/spec/modules/ccxBidAdapter_spec.js +++ b/test/spec/modules/ccxBidAdapter_spec.js @@ -495,78 +495,4 @@ describe('ccxAdapter', function () { expect(data.imp).to.deep.have.same.members(imps); }); }); - - describe('FLEDGE', function () { - it('should properly build a request when FLEDGE is enabled', async function () { - const bidderRequest = { - paapi: { - enabled: true - } - }; - const bids = [ - { - adUnitCode: 'banner', - auctionId: '0b9de793-8eda-481e-a548-aaaaaaaaaaa1', - bidId: '2e56e1af51ccc1', - bidder: 'ccx', - bidderRequestId: '17e7b9f58accc1', - mediaTypes: { - banner: { - sizes: [[300, 250]] - } - }, - params: { - placementId: 609 - }, - sizes: [[300, 250]], - transactionId: 'befddd38-cfa0-48ab-8bdd-bbbbbbbbbbb1', - ortb2Imp: { - ext: { - ae: 1 - } - } - } - ]; - - const ortbRequest = spec.buildRequests(bids, await addFPDToBidderRequest(bidderRequest)); - const data = JSON.parse(ortbRequest.data); - expect(data.imp[0].ext.ae).to.equal(1); - }); - - it('should properly build a request when FLEDGE is disabled', async function () { - const bidderRequest = { - paapi: { - enabled: false - } - }; - const bids = [ - { - adUnitCode: 'banner', - auctionId: '0b9de793-8eda-481e-a548-aaaaaaaaaaa2', - bidId: '2e56e1af51ccc2', - bidder: 'ccx', - bidderRequestId: '17e7b9f58accc2', - mediaTypes: { - banner: { - sizes: [[300, 250]] - } - }, - params: { - placementId: 610 - }, - sizes: [[300, 250]], - transactionId: 'befddd38-cfa0-48ab-8bdd-bbbbbbbbbbb2', - ortb2Imp: { - ext: { - ae: 1 - } - } - } - ]; - - const ortbRequest = spec.buildRequests(bids, await addFPDToBidderRequest(bidderRequest)); - const data = JSON.parse(ortbRequest.data); - expect(data.imp[0].ext.ae).to.be.undefined; - }); - }); }); diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index f6f6d31fe72..3b1595f824d 100644 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1872,70 +1872,6 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.imp[0].ext?.rwdd).to.equal(0); }); - it('should properly build a request when FLEDGE is enabled', async function () { - const bidderRequest = { - paapi: { - enabled: true - } - }; - const bidRequests = [ - { - bidder: 'criteo', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - ext: { - igs: { - ae: 1 - } - } - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.igs.ae).to.equal(1); - }); - - it('should properly build a request when FLEDGE is disabled', async function () { - const bidderRequest = { - paapi: { - enabled: false - }, - }; - const bidRequests = [ - { - bidder: 'criteo', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - ext: { - igs: { - ae: 1 - } - } - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.igs?.ae).to.be.undefined; - }); - it('should properly transmit the pubid and slot uid if available', async function () { const bidderRequest = { ortb2: { @@ -2462,154 +2398,6 @@ describe('The Criteo bidding adapter', function () { }); } - it('should properly parse a bid response with FLEDGE auction configs', async function () { - const auctionConfig1 = { - auctionSignals: {}, - decisionLogicUrl: 'https://grid-mercury.criteo.com/fledge/decision', - interestGroupBuyers: ['https://first-buyer-domain.com', 'https://second-buyer-domain.com'], - perBuyerSignals: { - 'https://first-buyer-domain.com': { - foo: 'bar', - }, - 'https://second-buyer-domain.com': { - foo: 'baz' - }, - }, - perBuyerTimeout: { - '*': 500, - 'buyer1': 100, - 'buyer2': 200 - }, - perBuyerGroupLimits: { - '*': 60, - 'buyer1': 300, - 'buyer2': 400 - }, - seller: 'https://seller-domain.com', - sellerTimeout: 500, - sellerSignals: { - foo: 'bar', - foo2: 'bar2', - floor: 1, - currency: 'USD', - perBuyerTimeout: { - 'buyer1': 100, - 'buyer2': 200 - }, - perBuyerGroupLimits: { - 'buyer1': 300, - 'buyer2': 400 - }, - }, - sellerCurrency: 'USD', - }; - const auctionConfig2 = { - auctionSignals: {}, - decisionLogicUrl: 'https://grid-mercury.criteo.com/fledge/decision', - interestGroupBuyers: ['https://first-buyer-domain.com', 'https://second-buyer-domain.com'], - perBuyerSignals: { - 'https://first-buyer-domain.com': { - foo: 'bar', - }, - 'https://second-buyer-domain.com': { - foo: 'baz' - }, - }, - perBuyerTimeout: { - '*': 500, - 'buyer1': 100, - 'buyer2': 200 - }, - perBuyerGroupLimits: { - '*': 60, - 'buyer1': 300, - 'buyer2': 400 - }, - seller: 'https://seller-domain.com', - sellerTimeout: 500, - sellerSignals: { - foo: 'bar', - floor: 1, - perBuyerTimeout: { - 'buyer1': 100, - 'buyer2': 200 - }, - perBuyerGroupLimits: { - 'buyer1': 300, - 'buyer2': 400 - }, - }, - sellerCurrency: '???' - }; - const bidRequests = [ - { - bidId: 'test-bidId', - bidder: 'criteo', - adUnitCode: 'bid-123', - transactionId: 'transaction-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - bidFloor: 1, - bidFloorCur: 'EUR' - } - }, - { - bidId: 'test-bidId-2', - bidder: 'criteo', - adUnitCode: 'bid-123', - transactionId: 'transaction-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - bidFloor: 1, - bidFloorCur: 'EUR' - } - }, - ]; - const response = { - ext: { - igi: [{ - impid: 'test-bidId', - igs: [{ - impid: 'test-bidId', - bidId: 'test-bidId', - config: auctionConfig1 - }] - }, { - impid: 'test-bidId-2', - igs: [{ - impid: 'test-bidId-2', - bidId: 'test-bidId-2', - config: auctionConfig2 - }] - }] - }, - }; - const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest)); - const interpretedResponse = spec.interpretResponse({body: response}, request); - expect(interpretedResponse).to.have.property('bids'); - expect(interpretedResponse).to.have.property('paapi'); - expect(interpretedResponse.bids).to.have.lengthOf(0); - expect(interpretedResponse.paapi).to.have.lengthOf(2); - expect(interpretedResponse.paapi[0]).to.deep.equal({ - bidId: 'test-bidId', - impid: 'test-bidId', - config: auctionConfig1, - }); - expect(interpretedResponse.paapi[1]).to.deep.equal({ - bidId: 'test-bidId-2', - impid: 'test-bidId-2', - config: auctionConfig2, - }); - }); - [{ hasBidResponseLevelPafData: true, hasBidResponseBidLevelPafData: true, diff --git a/test/spec/modules/debugging_mod_spec.js b/test/spec/modules/debugging_mod_spec.js index 4989eb7c2e3..488543de582 100644 --- a/test/spec/modules/debugging_mod_spec.js +++ b/test/spec/modules/debugging_mod_spec.js @@ -111,8 +111,8 @@ describe('bid interceptor', () => { }); describe('rule', () => { - function matchingRule({replace, options, paapi}) { - setRules({when: {}, then: replace, options: options, paapi}); + function matchingRule({replace, options}) { + setRules({when: {}, then: replace, options: options}); return interceptor.match({}); } @@ -172,48 +172,6 @@ describe('bid interceptor', () => { }); }); - describe('paapi', () => { - it('should accept literals', () => { - const mockConfig = [ - {config: {paapi: 1}}, - {config: {paapi: 2}} - ] - const paapi = matchingRule({paapi: mockConfig}).paapi({}); - expect(paapi).to.eql(mockConfig); - }); - - it('should accept a function and pass extra args to it', () => { - const paapiDef = sinon.stub(); - const args = [{}, {}, {}]; - matchingRule({paapi: paapiDef}).paapi(...args); - expect(paapiDef.calledOnceWith(...args.map(sinon.match.same))).to.be.true; - }); - - Object.entries({ - 'literal': (cfg) => [cfg], - 'function': (cfg) => () => [cfg] - }).forEach(([t, makeConfigs]) => { - describe(`when paapi is defined as a ${t}`, () => { - it('should wrap top-level configs in "config"', () => { - const cfg = {decisionLogicURL: 'example'}; - expect(matchingRule({paapi: makeConfigs(cfg)}).paapi({})).to.eql([{ - config: cfg - }]) - }); - - Object.entries({ - 'config': {config: 1}, - 'igb': {igb: 1}, - 'config and igb': {config: 1, igb: 2} - }).forEach(([t, cfg]) => { - it(`should not wrap configs that define top-level ${t}`, () => { - expect(matchingRule({paapi: makeConfigs(cfg)}).paapi({})).to.eql([cfg]); - }) - }) - }) - }) - }) - describe('.options', () => { it('should include default rule options', () => { const optDef = {someOption: 'value'}; @@ -231,17 +189,16 @@ describe('bid interceptor', () => { }); describe('intercept()', () => { - let done, addBid, addPaapiConfig; + let done, addBid; function intercept(args = {}) { const bidRequest = {bids: args.bids || []}; - return interceptor.intercept(Object.assign({bidRequest, done, addBid, addPaapiConfig}, args)); + return interceptor.intercept(Object.assign({bidRequest, done, addBid}, args)); } beforeEach(() => { done = sinon.spy(); addBid = sinon.spy(); - addPaapiConfig = sinon.spy(); }); describe('on no match', () => { @@ -304,20 +261,6 @@ describe('bid interceptor', () => { }); }); - it('should call addPaapiConfigs when provided', () => { - const mockPaapiConfigs = [ - {config: {paapi: 1}}, - {config: {paapi: 2}} - ] - setRules({ - when: {id: 2}, - paapi: mockPaapiConfigs, - }); - intercept({bidRequest: REQUEST}); - expect(addPaapiConfig.callCount).to.eql(2); - mockPaapiConfigs.forEach(cfg => sinon.assert.calledWith(addPaapiConfig, cfg)) - }) - it('should not call onBid when then is null', () => { setRules({ when: {id: 2}, @@ -357,7 +300,7 @@ describe('Debugging config', () => { }); describe('bidderBidInterceptor', () => { - let next, interceptBids, onCompletion, interceptResult, done, addBid, wrapCallback, addPaapiConfig, wrapped, bidderBidInterceptor; + let next, interceptBids, onCompletion, interceptResult, done, addBid, wrapCallback, wrapped, bidderBidInterceptor; function interceptorArgs({spec = {}, bids = [], bidRequest = {}, ajax = {}, cbs = {}} = {}) { return [next, interceptBids, spec, bids, bidRequest, ajax, wrapCallback, Object.assign({onCompletion}, cbs)]; @@ -381,7 +324,6 @@ describe('bidderBidInterceptor', () => { interceptBids = sinon.stub().callsFake((opts) => { done = opts.done; addBid = opts.addBid; - addPaapiConfig = opts.addPaapiConfig; return interceptResult; }); onCompletion = sinon.spy(); @@ -400,15 +342,6 @@ describe('bidderBidInterceptor', () => { expect(onBid.calledWith(sinon.match.same(bid))).to.be.true; }); - it('should pass addPaapiConfig that triggers onPaapi', () => { - const onPaapi = sinon.stub().callsFake(() => { - expect(wrapped).to.be.true; - }); - bidderBidInterceptor(...interceptorArgs({cbs: {onPaapi}})); - addPaapiConfig({paapi: 'config'}, {bidId: 'bidId'}); - sinon.assert.calledWith(onPaapi, {paapi: 'config', bidId: 'bidId'}) - }) - describe('with no remaining bids', () => { it('should pass a done callback that triggers onCompletion', () => { bidderBidInterceptor(...interceptorArgs()); diff --git a/test/spec/modules/freeWheelAdserverVideo_spec.js b/test/spec/modules/freeWheelAdserverVideo_spec.js deleted file mode 100644 index 3da5b411e37..00000000000 --- a/test/spec/modules/freeWheelAdserverVideo_spec.js +++ /dev/null @@ -1,350 +0,0 @@ -import { expect } from 'chai'; -import { adpodUtils } from 'modules/freeWheelAdserverVideo.js'; -import { auctionManager } from 'src/auctionManager.js'; -import { config } from 'src/config.js'; -import { server } from 'test/mocks/xhr.js'; - -describe('freeWheel adserver module', function() { - let amStub; - let amGetAdUnitsStub; - - before(function () { - const adUnits = [{ - code: 'preroll_1', - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 60, - durationRangeSec: [15, 30], - requireExactDuration: true - } - }, - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 14542875, - } - } - ] - }, { - code: 'midroll_1', - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 60, - durationRangeSec: [15, 30], - requireExactDuration: true - } - }, - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 14542875, - } - } - ] - }]; - - amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits'); - amGetAdUnitsStub.returns(adUnits); - amStub = sinon.stub(auctionManager, 'getBidsReceived'); - }); - - beforeEach(function () { - config.setConfig({ - adpod: { - brandCategoryExclusion: false, - deferCaching: false - } - }); - }) - - afterEach(function() { - config.resetConfig(); - }); - - after(function () { - amGetAdUnitsStub.restore(); - amStub.restore(); - }); - - it('should return targeting for all adunits', function() { - amStub.returns(getBidsReceived()); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['midroll_1'].length).to.equal(3); - }); - - it('should return targeting for passed adunit code', function() { - amStub.returns(getBidsReceived()); - let targeting; - adpodUtils.getTargeting({ - codes: ['preroll_1'], - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - expect(targeting['preroll_1']).to.exist; - expect(targeting['midroll_1']).to.not.exist; - }); - - it('should only use adpod bids', function() { - const bannerBid = [{ - 'ad': 'creative', - 'cpm': '1.99', - 'width': 300, - 'height': 250, - 'requestId': '1', - 'creativeId': 'some-id', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 360, - 'bidderCode': 'appnexus', - 'statusMessage': 'Bid available', - 'adId': '28f24ced14586c', - 'adUnitCode': 'preroll_1' - }]; - amStub.returns(getBidsReceived().concat(bannerBid)); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['midroll_1'].length).to.equal(3); - }); - - it('should return unique category bids when competitive exclusion is enabled', function() { - config.setConfig({ - adpod: { - brandCategoryExclusion: true, - deferCaching: false - } - }); - amStub.returns([ - createBid(10, 'preroll_1', 30, '10.00_395_30s', '123', '395'), - createBid(15, 'preroll_1', 30, '15.00_395_30s', '123', '395'), - createBid(15, 'midroll_1', 60, '15.00_406_60s', '123', '406'), - createBid(10, 'preroll_1', 30, '10.00_395_30s', '123', '395') - ]); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['midroll_1'].length).to.equal(2); - }); - - it('should only select bids less than adpod duration', function() { - amStub.returns([ - createBid(10, 'preroll_1', 90, '10.00_395_90s', '123', '395'), - createBid(15, 'preroll_1', 90, '15.00_395_90s', '123', '395'), - createBid(15, 'midroll_1', 90, '15.00_406_90s', '123', '406') - ]); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - expect(targeting['preroll_1']).to.be.empty; - expect(targeting['midroll_1']).to.be.empty; - }); - - it('should select bids when deferCaching is enabled', function() { - config.setConfig({ - adpod: { - deferCaching: true - } - }); - amStub.returns(getBidsReceived()); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - server.requests[0].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify({'responses': getBidsReceived().slice(0, 4)}) - ); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['midroll_1'].length).to.equal(3); - }); - - it('should prioritize bids with deal', function() { - config.setConfig({ - adpod: { - deferCaching: true, - prioritizeDeals: true - } - }); - - const tier6Bid = createBid(10, 'preroll_1', 15, 'tier6_395_15s', '123', '395'); - tier6Bid['video']['dealTier'] = 'tier6' - - const tier7Bid = createBid(11, 'preroll_1', 45, 'tier7_395_15s', '123', '395'); - tier7Bid['video']['dealTier'] = 'tier7' - - const bidsReceived = [ - tier6Bid, - tier7Bid, - createBid(15, 'preroll_1', 90, '15.00_395_90s', '123', '395'), - ] - amStub.returns(bidsReceived); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - server.requests[0].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify({'responses': bidsReceived.slice(1)}) - ); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['preroll_1']).to.deep.include({'hb_pb_cat_dur': 'tier6_395_15s'}); - expect(targeting['preroll_1']).to.deep.include({'hb_pb_cat_dur': 'tier7_395_15s'}); - expect(targeting['preroll_1']).to.deep.include({'hb_cache_id': '123'}); - }); - - it('should apply minDealTier to bids if configured', function() { - config.setConfig({ - adpod: { - deferCaching: true, - prioritizeDeals: true, - dealTier: { - 'appnexus': { - prefix: 'tier', - minDealTier: 5 - } - } - } - }); - - const tier2Bid = createBid(10, 'preroll_1', 15, 'tier2_395_15s', '123', '395'); - tier2Bid['video']['dealTier'] = 2 - tier2Bid['adserverTargeting']['hb_pb'] = '10.00' - - const tier7Bid = createBid(11, 'preroll_1', 45, 'tier7_395_15s', '123', '395'); - tier7Bid['video']['dealTier'] = 7 - tier7Bid['adserverTargeting']['hb_pb'] = '11.00' - - const bid = createBid(15, 'preroll_1', 15, '15.00_395_90s', '123', '395'); - bid['adserverTargeting']['hb_pb'] = '15.00' - - const bidsReceived = [ - tier2Bid, - tier7Bid, - bid - ] - amStub.returns(bidsReceived); - let targeting; - adpodUtils.getTargeting({ - callback: function(errorMsg, targetingResult) { - targeting = targetingResult; - } - }); - - server.requests[0].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify({'responses': [tier7Bid, bid]}) - ); - - expect(targeting['preroll_1'].length).to.equal(3); - expect(targeting['preroll_1']).to.deep.include({'hb_pb_cat_dur': 'tier7_395_15s'}); - expect(targeting['preroll_1']).to.deep.include({'hb_pb_cat_dur': '15.00_395_90s'}); - expect(targeting['preroll_1']).to.not.include({'hb_pb_cat_dur': 'tier2_395_15s'}); - expect(targeting['preroll_1']).to.deep.include({'hb_cache_id': '123'}); - }) -}); - -function getBidsReceived() { - return [ - createBid(10, 'preroll_1', 15, '10.00_395_15s', '123', '395'), - createBid(15, 'preroll_1', 15, '15.00_395_15s', '123', '395'), - createBid(15, 'midroll_1', 30, '15.00_406_30s', '123', '406'), - createBid(5, 'midroll_1', 5, '5.00_406_5s', '123', '406'), - createBid(20, 'midroll_1', 60, '20.00_406_60s', '123', '406'), - ] -} - -function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, industry) { - return { - 'bidderCode': 'appnexus', - 'width': 640, - 'height': 360, - 'statusMessage': 'Bid available', - 'adId': '28f24ced14586c', - 'mediaType': 'video', - 'source': 'client', - 'requestId': '28f24ced14586c', - 'cpm': cpm, - 'creativeId': 97517771, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 3600, - 'adUnitCode': adUnitCode, - 'video': { - 'context': 'adpod', - 'durationBucket': durationBucket - }, - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'vastUrl': 'http://some-vast-url.com', - 'vastImpUrl': 'http://some-vast-imp-url.com', - 'auctionId': 'ec266b31-d652-49c5-8295-e83fafe5532b', - 'responseTimestamp': 1548442460888, - 'requestTimestamp': 1548442460827, - 'bidder': 'appnexus', - 'timeToRespond': 61, - 'pbLg': '5.00', - 'pbMg': '5.00', - 'pbHg': '5.00', - 'pbAg': '5.00', - 'pbDg': '5.00', - 'pbCg': '', - 'size': '640x360', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '28f24ced14586c', - 'hb_pb': '5.00', - 'hb_size': '640x360', - 'hb_source': 'client', - 'hb_format': 'video', - 'hb_pb_cat_dur': priceIndustryDuration, - 'hb_cache_id': uuid - }, - 'customCacheKey': `${priceIndustryDuration}_${uuid}`, - 'meta': { - 'primaryCatId': 'iab-1', - 'adServerCatId': industry - }, - 'videoCacheKey': '4cf395af-8fee-4960-af0e-88d44e399f14' - } -} diff --git a/test/spec/modules/gamAdpod_spec.js b/test/spec/modules/gamAdpod_spec.js deleted file mode 100644 index 31e142d11f8..00000000000 --- a/test/spec/modules/gamAdpod_spec.js +++ /dev/null @@ -1,257 +0,0 @@ -import {auctionManager} from '../../../src/auctionManager.js'; -import {config} from '../../../src/config.js'; -import {gdprDataHandler, uspDataHandler} from '../../../src/consentHandler.js'; -import parse from 'url-parse'; -import {buildAdpodVideoUrl} from '../../../modules/gamAdpod.js'; -import {expect} from 'chai/index.js'; -import * as utils from '../../../src/utils.js'; -import {server} from '../../mocks/xhr.js'; -import * as adpod from 'modules/adpod.js'; - -describe('gamAdpod', function () { - let amStub; - let amGetAdUnitsStub; - - before(function () { - const adUnits = [{ - code: 'adUnitCode-1', - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 60, - durationRangeSec: [15, 30], - requireExactDuration: true - } - }, - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 14542875, - } - } - ] - }]; - - amGetAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits'); - amGetAdUnitsStub.returns(adUnits); - amStub = sinon.stub(auctionManager, 'getBidsReceived'); - }); - - beforeEach(function () { - config.setConfig({ - adpod: { - brandCategoryExclusion: true, - deferCaching: false - } - }); - }) - - afterEach(function() { - config.resetConfig(); - }); - - after(function () { - amGetAdUnitsStub.restore(); - amStub.restore(); - }); - - function getBidsReceived() { - return [ - createBid(10, 'adUnitCode-1', 15, '10.00_395_15s', '123', '395', '10.00'), - createBid(15, 'adUnitCode-1', 15, '15.00_395_15s', '123', '395', '15.00'), - createBid(25, 'adUnitCode-1', 30, '15.00_406_30s', '123', '406', '25.00'), - ] - } - - function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, label, hbpb) { - return { - 'bidderCode': 'appnexus', - 'width': 640, - 'height': 360, - 'statusMessage': 'Bid available', - 'adId': '28f24ced14586c', - 'mediaType': 'video', - 'source': 'client', - 'requestId': '28f24ced14586c', - 'cpm': cpm, - 'creativeId': 97517771, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 3600, - 'adUnitCode': adUnitCode, - 'video': { - 'context': 'adpod', - 'durationBucket': durationBucket - }, - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'vastUrl': 'http://some-vast-url.com', - 'vastImpUrl': 'http://some-vast-imp-url.com', - 'auctionId': 'ec266b31-d652-49c5-8295-e83fafe5532b', - 'responseTimestamp': 1548442460888, - 'requestTimestamp': 1548442460827, - 'bidder': 'appnexus', - 'timeToRespond': 61, - 'pbLg': '5.00', - 'pbMg': '5.00', - 'pbHg': '5.00', - 'pbAg': '5.00', - 'pbDg': '5.00', - 'pbCg': '', - 'size': '640x360', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '28f24ced14586c', - 'hb_pb': hbpb, - 'hb_size': '640x360', - 'hb_source': 'client', - 'hb_format': 'video', - 'hb_pb_cat_dur': priceIndustryDuration, - 'hb_cache_id': uuid - }, - 'customCacheKey': `${priceIndustryDuration}_${uuid}`, - 'meta': { - 'primaryCatId': 'iab-1', - 'adServerCatId': label - }, - 'videoCacheKey': '4cf395af-8fee-4960-af0e-88d44e399f14' - } - } - - it('should return masterTag url', function() { - amStub.returns(getBidsReceived()); - const uspDataHandlerStub = sinon.stub(uspDataHandler, 'getConsentData'); - uspDataHandlerStub.returns('1YYY'); - const gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData'); - gdprDataHandlerStub.returns({ - gdprApplies: true, - consentString: 'consent', - addtlConsent: 'moreConsent' - }); - let url; - parse(buildAdpodVideoUrl({ - code: 'adUnitCode-1', - callback: handleResponse, - params: { - 'iu': 'my/adUnit', - 'description_url': 'someUrl.com', - } - })); - - function handleResponse(err, masterTag) { - if (err) { - return; - } - url = parse(masterTag); - - expect(url.protocol).to.equal('https:'); - expect(url.host).to.equal('securepubads.g.doubleclick.net'); - - const queryParams = utils.parseQS(url.query); - expect(queryParams).to.have.property('correlator'); - expect(queryParams).to.have.property('description_url', 'someUrl.com'); - expect(queryParams).to.have.property('env', 'vp'); - expect(queryParams).to.have.property('gdfp_req', '1'); - expect(queryParams).to.have.property('iu', 'my/adUnit'); - expect(queryParams).to.have.property('output', 'vast'); - expect(queryParams).to.have.property('sz', '640x480'); - expect(queryParams).to.have.property('unviewed_position_start', '1'); - expect(queryParams).to.have.property('url'); - expect(queryParams).to.have.property('cust_params'); - expect(queryParams).to.have.property('gdpr', '1'); - expect(queryParams).to.have.property('gdpr_consent', 'consent'); - expect(queryParams).to.have.property('addtl_consent', 'moreConsent'); - - const custParams = utils.parseQS(decodeURIComponent(queryParams.cust_params)); - expect(custParams).to.have.property('hb_cache_id', '123'); - expect(custParams).to.have.property('hb_pb_cat_dur', '15.00_395_15s,15.00_406_30s,10.00_395_15s'); - uspDataHandlerStub.restore(); - gdprDataHandlerStub.restore(); - } - }); - - it('should return masterTag url with correct custom params when brandCategoryExclusion is false', function() { - config.setConfig({ - adpod: { - brandCategoryExclusion: false, - } - }); - function getBids() { - const bids = [ - createBid(10, 'adUnitCode-1', 15, '10.00_15s', '123', '395', '10.00'), - createBid(15, 'adUnitCode-1', 15, '15.00_15s', '123', '395', '15.00'), - createBid(25, 'adUnitCode-1', 30, '15.00_30s', '123', '406', '25.00'), - ]; - bids.forEach((bid) => { - delete bid.meta; - }); - return bids; - } - amStub.returns(getBids()); - let url; - parse(buildAdpodVideoUrl({ - code: 'adUnitCode-1', - callback: handleResponse, - params: { - 'iu': 'my/adUnit', - 'description_url': 'someUrl.com', - } - })); - - function handleResponse(err, masterTag) { - if (err) { - return; - } - url = parse(masterTag); - expect(url.protocol).to.equal('https:'); - expect(url.host).to.equal('securepubads.g.doubleclick.net'); - - const queryParams = utils.parseQS(url.query); - expect(queryParams).to.have.property('correlator'); - expect(queryParams).to.have.property('description_url', 'someUrl.com'); - expect(queryParams).to.have.property('env', 'vp'); - expect(queryParams).to.have.property('gdfp_req', '1'); - expect(queryParams).to.have.property('iu', 'my/adUnit'); - expect(queryParams).to.have.property('output', 'xml_vast3'); - expect(queryParams).to.have.property('sz', '640x480'); - expect(queryParams).to.have.property('unviewed_position_start', '1'); - expect(queryParams).to.have.property('url'); - expect(queryParams).to.have.property('cust_params'); - - const custParams = utils.parseQS(decodeURIComponent(queryParams.cust_params)); - expect(custParams).to.have.property('hb_cache_id', '123'); - expect(custParams).to.have.property('hb_pb_cat_dur', '10.00_15s,15.00_15s,15.00_30s'); - } - }); - - it('should handle error when cache fails', function() { - config.setConfig({ - adpod: { - brandCategoryExclusion: true, - deferCaching: true - } - }); - amStub.returns(getBidsReceived()); - - parse(buildAdpodVideoUrl({ - code: 'adUnitCode-1', - callback: handleResponse, - params: { - 'iu': 'my/adUnit', - 'description_url': 'someUrl.com', - } - })); - - server.requests[0].respond(503, { - 'Content-Type': 'plain/text', - }, 'The server could not save anything at the moment.'); - - function handleResponse(err, masterTag) { - expect(masterTag).to.be.null; - expect(err).to.be.an('error'); - } - }); -}) diff --git a/test/spec/modules/gmosspBidAdapter_spec.js b/test/spec/modules/gmosspBidAdapter_spec.js index b3d0c20f3d4..e18ce39109a 100644 --- a/test/spec/modules/gmosspBidAdapter_spec.js +++ b/test/spec/modules/gmosspBidAdapter_spec.js @@ -72,7 +72,7 @@ describe('GmosspAdapter', function () { const requests = spec.buildRequests(bidRequests, bidderRequest); expect(requests[0].url).to.equal(ENDPOINT); expect(requests[0].method).to.equal('GET'); - expect(requests[0].data).to.equal('tid=791e9d84-af92-4903-94da-24c7426d9d0c&bid=2b84475b5b636e&ver=$prebid.version$&sid=123456&im_uid=h.0a4749e7ffe09fa6&shared_id=1111&idl_env=1111&url=https%3A%2F%2Fhoge.com' + '&ref=' + encodeURIComponent(document.referrer) + '&cur=JPY&dnt=0&'); + expect(requests[0].data).to.equal('tid=791e9d84-af92-4903-94da-24c7426d9d0c&bid=2b84475b5b636e&ver=$prebid.version$&sid=123456&im_uid=h.0a4749e7ffe09fa6&shared_id=1111&idl_env=1111&url=https%3A%2F%2Fhoge.com' + '&ref=' + encodeURIComponent(document.referrer) + '&cur=JPY&'); }); it('should use fallback if refererInfo.referer in bid request is empty and im_uid ,shared_id, idl_env cookie is empty', function () { @@ -86,7 +86,7 @@ describe('GmosspAdapter', function () { bidRequests[0].userId.idl_env = ''; const requests = spec.buildRequests(bidRequests, bidderRequest); - const result = 'tid=791e9d84-af92-4903-94da-24c7426d9d0c&bid=2b84475b5b636e&ver=$prebid.version$&sid=123456&ref=' + encodeURIComponent(document.referrer) + '&cur=JPY&dnt=0&'; + const result = 'tid=791e9d84-af92-4903-94da-24c7426d9d0c&bid=2b84475b5b636e&ver=$prebid.version$&sid=123456&ref=' + encodeURIComponent(document.referrer) + '&cur=JPY&'; expect(requests[0].data).to.equal(result); }); }); diff --git a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js index 266bc104fd8..e871ec4c16d 100644 --- a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js +++ b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js @@ -22,7 +22,6 @@ describe('growthCode analytics adapter', () => { 'bidResponse', 'setTargeting', 'requestBids', - 'addAdUnits', 'noBid', 'bidWon', 'bidderDone'] diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 1ceaf4f2646..95b4228e95a 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -332,24 +332,6 @@ describe('gumgumAdapter', function () { expect(bidRequest.data).to.have.property('gpid'); expect(bidRequest.data.gpid).to.equal('/17037559/jeusol/jeusol_D_1'); }); - it('should set ae value to 1 for PAAPI', function () { - const req = { ...bidRequests[0], - ortb2Imp: { - ext: { - ae: 1, - data: { - adserver: { - name: 'test', - adslot: 123456 - } - } - } - } } - const bidRequest = spec.buildRequests([req])[0]; - expect(bidRequest.data).to.have.property('ae'); - expect(bidRequest.data.ae).to.equal(true); - }); - it('should set the global placement id (gpid) if in gpid property', function () { const gpid = 'abc123' const req = { ...bidRequests[0], ortb2Imp: { ext: { data: {}, gpid } } } diff --git a/test/spec/modules/hadronAnalyticsAdapter_spec.js b/test/spec/modules/hadronAnalyticsAdapter_spec.js index 68e5bc3aecb..ec1092fa441 100644 --- a/test/spec/modules/hadronAnalyticsAdapter_spec.js +++ b/test/spec/modules/hadronAnalyticsAdapter_spec.js @@ -12,7 +12,7 @@ describe('Hadron analytics adapter', () => { options: { partnerId: 12349, eventsToTrack: ['auctionInit', 'auctionEnd', 'bidWon', - 'bidderDone', 'requestBids', 'addAdUnits', 'setTargeting', 'adRenderFailed', + 'bidderDone', 'requestBids', 'setTargeting', 'adRenderFailed', 'bidResponse', 'bidTimeout', 'bidRequested', 'bidAdjustment', 'nonExistingEvent' ], } diff --git a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js index 71182d146a0..76fda979811 100644 --- a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +++ b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js @@ -161,7 +161,6 @@ describe('Invisibly Analytics Adapter test suite', function () { REQUEST_BIDS: { call: 'request', }, - ADD_AD_UNITS: { call: 'addAdUnits' }, AD_RENDER_FAILED: { call: 'adRenderFailed' }, INVALID_EVENT: { mockKey: 'this event should not emit', @@ -447,28 +446,6 @@ describe('Invisibly Analytics Adapter test suite', function () { sinon.assert.callCount(invisiblyAdapter.track, 1); }); - // spec for add ad units event - it('add ad units event', function () { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse( - requests[0].requestBody.substring(0) - ); - expect(requests.length).to.equal(1); - expect(requests[0].url).to.equal( - 'https://api.pymx5.com/v1/sites/events' - ); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_addAdUnits'); - expect(invisiblyEvents.event_data.call).to.equal( - MOCK.ADD_AD_UNITS.call - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); - // spec for ad render failed event it('ad render failed event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); @@ -540,7 +517,6 @@ describe('Invisibly Analytics Adapter test suite', function () { EVENTS.BIDDER_DONE, EVENTS.SET_TARGETING, EVENTS.REQUEST_BIDS, - EVENTS.ADD_AD_UNITS, EVENTS.AD_RENDER_FAILED ]).to.beTrackedBy(invisiblyAdapter.track); }); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index eb352fa4ebe..1a5bd0f1c01 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -884,52 +884,6 @@ describe('IndexexchangeAdapter', function () { } }; - const DEFAULT_OPTION_FLEDGE_ENABLED_GLOBALLY = { - gdprConsent: { - gdprApplies: true, - consentString: '3huaa11=qu3198ae', - vendorData: {} - }, - refererInfo: { - page: 'https://www.prebid.org', - canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' - }, - ortb2: { - site: { - page: 'https://www.prebid.org' - }, - source: { - tid: 'mock-tid' - } - }, - paapi: { - enabled: true - }, - }; - - const DEFAULT_OPTION_FLEDGE_ENABLED = { - gdprConsent: { - gdprApplies: true, - consentString: '3huaa11=qu3198ae', - vendorData: {} - }, - refererInfo: { - page: 'https://www.prebid.org', - canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' - }, - ortb2: { - site: { - page: 'https://www.prebid.org' - }, - source: { - tid: 'mock-tid' - } - }, - paapi: { - enabled: true - } - }; - const DEFAULT_IDENTITY_RESPONSE = { IdentityIp: { responsePending: false, @@ -1055,10 +1009,8 @@ describe('IndexexchangeAdapter', function () { id: `uid_id_${i}`, }] }; - eids.push(newEid); } - return eids; } @@ -3629,78 +3581,6 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('buildRequestFledge', function () { - it('impression should have ae=1 in ext when fledge module is enabled and ae is set in ad unit', function () { - const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]); - const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0]; - const impression = extractPayload(requestBidFloor).imp[0]; - - expect(impression.ext.ae).to.equal(1); - }); - - it('impression should have ae=1 in ext when request has paapi.enabled = true and ext.ae = 1', function () { - const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]); - const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0]; - const impression = extractPayload(requestBidFloor).imp[0]; - - expect(impression.ext.ae).to.equal(1); - }); - - it('impression should not have ae=1 in ext when fledge module is enabled globally through setConfig but overidden at ad unit level', function () { - const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); - const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0]; - const impression = extractPayload(requestBidFloor).imp[0]; - - expect(impression.ext.ae).to.be.undefined; - }); - - it('impression should not have ae=1 in ext when fledge module is disabled', function () { - const bidderRequest = deepClone(DEFAULT_OPTION); - const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); - const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0]; - const impression = extractPayload(requestBidFloor).imp[0]; - - expect(impression.ext.ae).to.be.undefined; - }); - - it('should contain correct IXdiag ae property for Fledge', function () { - const bid = DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]; - const bidderRequestWithFledgeEnabled = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - const request = spec.buildRequests([bid], bidderRequestWithFledgeEnabled); - const diagObj = extractPayload(request[0]).ext.ixdiag; - expect(diagObj.ae).to.equal(true); - }); - - it('should log warning for non integer auction environment in ad unit for fledge', () => { - const logWarnSpy = sinon.spy(utils, 'logWarn'); - const bid = DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]; - bid.ortb2Imp.ext.ae = 'malformed' - const bidderRequestWithFledgeEnabled = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - spec.buildRequests([bid], bidderRequestWithFledgeEnabled); - expect(logWarnSpy.calledWith('error setting auction environment flag - must be an integer')).to.be.true; - logWarnSpy.restore(); - }); - - it('impression should have paapi extension when passed', function () { - const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED); - const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]); - bid.ortb2Imp.ext.ae = 1 - bid.ortb2Imp.ext.paapi = { - requestedSize: { - width: 300, - height: 250 - } - } - const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0]; - const impression = extractPayload(requestBidFloor).imp[0]; - expect(impression.ext.paapi.requestedSize.width).to.equal(300); - expect(impression.ext.paapi.requestedSize.height).to.equal(250); - }); - }); - describe('integration through exchangeId and externalId', function () { const expectedExchangeId = 123456; // create banner bids with externalId but no siteId as bidder param @@ -4346,106 +4226,6 @@ describe('IndexexchangeAdapter', function () { expect(result[0]).to.deep.equal(expectedParse[0]); }); - describe('Auction config response', function () { - let bidderRequestWithFledgeEnabled; - let serverResponseWithoutFledgeConfigs; - let serverResponseWithFledgeConfigs; - let serverResponseWithMalformedAuctionConfig; - let serverResponseWithMalformedAuctionConfigs; - - beforeEach(() => { - bidderRequestWithFledgeEnabled = spec.buildRequests(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED, {})[0]; - bidderRequestWithFledgeEnabled.paapi = {enabled: true}; - - serverResponseWithoutFledgeConfigs = { - body: { - ...DEFAULT_BANNER_BID_RESPONSE - } - }; - - serverResponseWithFledgeConfigs = { - body: { - ...DEFAULT_BANNER_BID_RESPONSE, - ext: { - protectedAudienceAuctionConfigs: [ - { - bidId: '59f219e54dc2fc', - config: { - seller: 'https://seller.test.indexexchange.com', - decisionLogicUrl: 'https://seller.test.indexexchange.com/decision-logic.js', - interestGroupBuyers: ['https://buyer.test.indexexchange.com'], - sellerSignals: { - callbackURL: 'https://test.com/ig/v1/ck74j8bcvc9c73a8eg6g' - }, - perBuyerSignals: { - 'https://buyer.test.indexexchange.com': {} - } - } - } - ] - } - } - }; - - serverResponseWithMalformedAuctionConfig = { - body: { - ...DEFAULT_BANNER_BID_RESPONSE, - ext: { - protectedAudienceAuctionConfigs: ['malformed'] - } - } - }; - - serverResponseWithMalformedAuctionConfigs = { - body: { - ...DEFAULT_BANNER_BID_RESPONSE, - ext: { - protectedAudienceAuctionConfigs: 'malformed' - } - } - }; - }); - - it('should correctly interpret response with auction configs', () => { - const result = spec.interpretResponse(serverResponseWithFledgeConfigs, bidderRequestWithFledgeEnabled); - const expectedOutput = [ - { - bidId: '59f219e54dc2fc', - config: { - ...serverResponseWithFledgeConfigs.body.ext.protectedAudienceAuctionConfigs[0].config, - perBuyerSignals: { - 'https://buyer.test.indexexchange.com': {} - } - } - } - ]; - expect(result.paapi).to.deep.equal(expectedOutput); - }); - - it('should correctly interpret response without auction configs', () => { - const result = spec.interpretResponse(serverResponseWithoutFledgeConfigs, bidderRequestWithFledgeEnabled); - expect(result.paapi).to.be.undefined; - }); - - it('should handle malformed auction configs gracefully', () => { - const result = spec.interpretResponse(serverResponseWithMalformedAuctionConfig, bidderRequestWithFledgeEnabled); - expect(result.paapi).to.be.empty; - }); - - it('should log warning for malformed auction configs', () => { - const logWarnSpy = sinon.spy(utils, 'logWarn'); - spec.interpretResponse(serverResponseWithMalformedAuctionConfig, bidderRequestWithFledgeEnabled); - expect(logWarnSpy.calledWith('Malformed auction config detected:', 'malformed')).to.be.true; - logWarnSpy.restore(); - }); - - it('should return bids when protected audience auction conigs is malformed', () => { - const result = spec.interpretResponse(serverResponseWithMalformedAuctionConfigs, bidderRequestWithFledgeEnabled); - expect(result.paapi).to.be.undefined; - expect(result.length).to.be.greaterThan(0); - }); - }); - describe('interpretResponse when server response is empty', function() { let serverResponseWithoutBody; let serverResponseWithoutSeatbid; @@ -4480,7 +4260,6 @@ describe('IndexexchangeAdapter', function () { }); }); }); - describe('bidrequest consent', function () { it('should have consent info if gdprApplies and consentString exist', function () { const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index c376b444246..7a5587cbf36 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1900,55 +1900,6 @@ describe('kargo adapter tests', function() { advertiserDomains: [ 'https://foo.com', 'https://bar.com' ] }); }); - - it('should return paapi if provided in bid response', function () { - const auctionConfig = { - seller: 'https://kargo.com', - decisionLogicUrl: 'https://kargo.com/decision_logic.js', - interestGroupBuyers: ['https://some_buyer.com'], - perBuyerSignals: { - 'https://some_buyer.com': { a: 1 } - } - } - - const body = response.body; - for (const key in body) { - if (body.hasOwnProperty(key)) { - if (key % 2 !== 0) { // Add auctionConfig to every other object - body[key].auctionConfig = auctionConfig; - } - } - } - - const result = spec.interpretResponse(response, bidderRequest); - - // Test properties of bidResponses - result.bids.forEach(bid => { - expect(bid).to.have.property('requestId'); - expect(bid).to.have.property('cpm'); - expect(bid).to.have.property('width'); - expect(bid).to.have.property('height'); - expect(bid).to.have.property('ttl'); - expect(bid).to.have.property('creativeId'); - expect(bid.netRevenue).to.be.true; - expect(bid).to.have.property('meta').that.is.an('object'); - }); - - // Test properties of paapi - expect(result.paapi).to.have.lengthOf(3); - - const expectedBidIds = ['1', '3', '5']; // Expected bidIDs - result.paapi.forEach(config => { - expect(config).to.have.property('bidId'); - expect(expectedBidIds).to.include(config.bidId); - - expect(config).to.have.property('config').that.is.an('object'); - expect(config.config).to.have.property('seller', 'https://kargo.com'); - expect(config.config).to.have.property('decisionLogicUrl', 'https://kargo.com/decision_logic.js'); - expect(config.config.interestGroupBuyers).to.be.an('array').that.includes('https://some_buyer.com'); - expect(config.config.perBuyerSignals).to.have.property('https://some_buyer.com').that.deep.equals({ a: 1 }); - }); - }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/logicadBidAdapter_spec.js b/test/spec/modules/logicadBidAdapter_spec.js index 24cc1faae62..715c4007fd6 100644 --- a/test/spec/modules/logicadBidAdapter_spec.js +++ b/test/spec/modules/logicadBidAdapter_spec.js @@ -36,11 +36,6 @@ describe('LogicadAdapter', function () { } }] }], - ortb2Imp: { - ext: { - ae: 1 - } - }, ortb2: { device: { sua: { @@ -197,9 +192,6 @@ describe('LogicadAdapter', function () { stack: [] }, auctionStart: 1563337198010, - paapi: { - enabled: true - } }; const serverResponse = { body: { @@ -227,48 +219,6 @@ describe('LogicadAdapter', function () { } }; - const paapiServerResponse = { - body: { - seatbid: - [{ - bid: { - requestId: '51ef8751f9aead', - cpm: 101.0234, - width: 300, - height: 250, - creativeId: '2019', - currency: 'JPY', - netRevenue: true, - ttl: 60, - ad: '

TEST
', - meta: { - advertiserDomains: ['logicad.com'] - } - } - }], - ext: { - fledgeAuctionConfigs: [{ - bidId: '51ef8751f9aead', - config: { - seller: 'https://fledge.ladsp.com', - decisionLogicUrl: 'https://fledge.ladsp.com/decision_logic.js', - interestGroupBuyers: ['https://fledge.ladsp.com'], - requestedSize: {width: '300', height: '250'}, - allSlotsRequestedSizes: [{width: '300', height: '250'}], - sellerSignals: {signal: 'signal'}, - sellerTimeout: '500', - perBuyerSignals: {'https://fledge.ladsp.com': {signal: 'signal'}}, - perBuyerCurrencies: {'https://fledge.ladsp.com': 'USD'} - } - }] - }, - userSync: { - type: 'image', - url: 'https://cr-p31.ladsp.jp/cookiesender/31' - } - } - }; - const nativeServerResponse = { body: { seatbid: @@ -339,10 +289,6 @@ describe('LogicadAdapter', function () { const data = JSON.parse(request.data); expect(data.auctionId).to.equal('18fd8b8b0bd757'); - // Protected Audience API flag - expect(data.bids[0]).to.have.property('ae'); - expect(data.bids[0].ae).to.equal(1); - expect(data.eids[0].source).to.equal('sharedid.org'); expect(data.eids[0].uids[0].id).to.equal('fakesharedid'); @@ -407,13 +353,6 @@ describe('LogicadAdapter', function () { expect(interpretedResponse[0].ttl).to.equal(serverResponse.body.seatbid[0].bid.ttl); expect(interpretedResponse[0].meta.advertiserDomains).to.equal(serverResponse.body.seatbid[0].bid.meta.advertiserDomains); - // Protected Audience API - const paapiRequest = spec.buildRequests(bidRequests, bidderRequest)[0]; - const paapiInterpretedResponse = spec.interpretResponse(paapiServerResponse, paapiRequest); - expect(paapiInterpretedResponse).to.have.property('bids'); - expect(paapiInterpretedResponse).to.have.property('paapi'); - expect(paapiInterpretedResponse.paapi[0]).to.deep.equal(paapiServerResponse.body.ext.fledgeAuctionConfigs[0]); - // native const nativeRequest = spec.buildRequests(nativeBidRequests, bidderRequest)[0]; const interpretedResponseForNative = spec.interpretResponse(nativeServerResponse, nativeRequest); diff --git a/test/spec/modules/luceadBidAdapter_spec.js b/test/spec/modules/luceadBidAdapter_spec.js index 464a467e9b2..91e50f9452d 100755 --- a/test/spec/modules/luceadBidAdapter_spec.js +++ b/test/spec/modules/luceadBidAdapter_spec.js @@ -2,7 +2,6 @@ import { expect } from 'chai'; import { spec } from 'modules/luceadBidAdapter.js'; import sinon from 'sinon'; import { newBidder } from 'src/adapters/bidderFactory.js'; -import {deepClone} from 'src/utils.js'; import * as ajax from 'src/ajax.js'; describe('Lucead Adapter', () => { @@ -172,12 +171,5 @@ describe('Lucead Adapter', () => { const result = spec.interpretResponse(serverResponse, bidRequest); expect(Object.keys(result.bids[0].meta)).to.include.members(['advertiserDomains']); }); - - it('should support enable_pa = false', function () { - serverResponse.body.enable_pa = false; - const result = spec.interpretResponse(serverResponse, bidRequest); - expect(result).to.be.an('array'); - expect(result[0].cpm).to.be.greaterThan(0); - }); }); }); diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index 83a5b83f774..6c293a3bb44 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -25,7 +25,6 @@ const { BID_WON, BID_TIMEOUT, BILLABLE_EVENT, - SEAT_NON_BID, PBS_ANALYTICS, BID_REJECTED } = EVENTS; @@ -169,7 +168,7 @@ const MOCK = { getStatusCode: () => 1, metrics }, - SEAT_NON_BID: { + PBS_ANALYTICS: { auctionId: '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', seatnonbid: [{ seat: 'rubicon', @@ -2359,7 +2358,7 @@ describe('magnite analytics adapter', function () { accountId: 1001 } }); - seatnonbid = utils.deepClone(MOCK.SEAT_NON_BID); + seatnonbid = utils.deepClone(MOCK.PBS_ANALYTICS); }); it('adds seatnonbid info to bids array', () => { diff --git a/test/spec/modules/marsmediaBidAdapter_spec.js b/test/spec/modules/marsmediaBidAdapter_spec.js index c8a0109a94b..cdfda655af3 100644 --- a/test/spec/modules/marsmediaBidAdapter_spec.js +++ b/test/spec/modules/marsmediaBidAdapter_spec.js @@ -1,6 +1,5 @@ import { spec } from 'modules/marsmediaBidAdapter.js'; import * as utils from 'src/utils.js'; -import * as dnt from 'libraries/dnt/index.js'; import { config } from 'src/config.js'; import { internal, resetWinDimensions } from '../../../src/utils.js'; @@ -399,15 +398,10 @@ describe('marsmedia adapter tests', function () { expect(openrtbRequest.imp[0].banner.format.length).to.equal(1); }); - it('dnt is correctly set to 1', function () { - var dntStub = sinon.stub(dnt, 'getDNT').returns(1); - + it('dnt is always 0', function () { var bidRequest = marsAdapter.buildRequests(this.defaultBidRequestList, this.defaultBidderRequest); - - dntStub.restore(); - const openrtbRequest = JSON.parse(bidRequest.data); - expect(openrtbRequest.device.dnt).to.equal(1); + expect(openrtbRequest.device.dnt).to.equal(0); }); it('supports string video sizes', function () { diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index 6ae86dc0801..a0cb4b57a38 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -1,7 +1,6 @@ import {assert} from 'chai'; import {spec, resolveFloor} from 'modules/mediaforceBidAdapter.js'; import * as utils from '../../../src/utils.js'; -import { getDNT } from 'libraries/dnt/index.js'; import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; describe('mediaforce bid adapter', function () { @@ -126,7 +125,7 @@ describe('mediaforce bid adapter', function () { ] }; - const dnt = getDNT() ? 1 : 0; + const dnt = 0; // DNT deprecated by W3C; Prebid no longer supports DNT const secure = window.location.protocol === 'https:' ? 1 : 0; const pageUrl = window.location.href; const timeout = 1500; diff --git a/test/spec/modules/mediafuseBidAdapter_spec.js b/test/spec/modules/mediafuseBidAdapter_spec.js index ff806d91f2c..d2142a5c14e 100644 --- a/test/spec/modules/mediafuseBidAdapter_spec.js +++ b/test/spec/modules/mediafuseBidAdapter_spec.js @@ -347,185 +347,6 @@ describe('MediaFuseAdapter', function () { expect(payload.tags[0].reserve).to.exist.and.to.equal(3); }); - it('should duplicate adpod placements into batches and set correct maxduration', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - - // 300 / 15 = 20 total - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(5); - - expect(payload1.tags[0]).to.deep.equal(payload1.tags[1]); - expect(payload1.tags[0].video.maxduration).to.equal(30); - - expect(payload2.tags[0]).to.deep.equal(payload1.tags[1]); - expect(payload2.tags[0].video.maxduration).to.equal(30); - }); - - it('should round down adpod placements when numbers are uneven', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 123, - durationRangeSec: [45], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - expect(payload.tags.length).to.equal(2); - }); - - it('should duplicate adpod placements when requireExactDuration is set', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - requireExactDuration: true, - } - } - } - ); - - // 20 total placements with 15 max impressions = 2 requests - const request = spec.buildRequests([bidRequest]); - expect(request.length).to.equal(2); - - // 20 spread over 2 requests = 15 in first request, 5 in second - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(5); - - // 10 placements should have max/min at 15 - // 10 placemenst should have max/min at 30 - const payload1tagsWith15 = payload1.tags.filter(tag => tag.video.maxduration === 15); - const payload1tagsWith30 = payload1.tags.filter(tag => tag.video.maxduration === 30); - expect(payload1tagsWith15.length).to.equal(10); - expect(payload1tagsWith30.length).to.equal(5); - - // 5 placemenst with min/max at 30 were in the first request - // so 5 remaining should be in the second - const payload2tagsWith30 = payload2.tags.filter(tag => tag.video.maxduration === 30); - expect(payload2tagsWith30.length).to.equal(5); - }); - - it('should set durations for placements when requireExactDuration is set and numbers are uneven', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 105, - durationRangeSec: [15, 30, 60], - requireExactDuration: true, - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - expect(payload.tags.length).to.equal(7); - - const tagsWith15 = payload.tags.filter(tag => tag.video.maxduration === 15); - const tagsWith30 = payload.tags.filter(tag => tag.video.maxduration === 30); - const tagsWith60 = payload.tags.filter(tag => tag.video.maxduration === 60); - expect(tagsWith15.length).to.equal(3); - expect(tagsWith30.length).to.equal(3); - expect(tagsWith60.length).to.equal(1); - }); - - it('should break adpod request into batches', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 225, - durationRangeSec: [5], - } - } - } - ); - - const request = spec.buildRequests([bidRequest]); - const payload1 = JSON.parse(request[0].data); - const payload2 = JSON.parse(request[1].data); - const payload3 = JSON.parse(request[2].data); - - expect(payload1.tags.length).to.equal(15); - expect(payload2.tags.length).to.equal(15); - expect(payload3.tags.length).to.equal(15); - }); - - it('should contain hb_source value for adpod', function() { - const bidRequest = Object.assign({}, - bidRequests[0], - { - params: { placementId: '14542875' } - }, - { - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - } - } - } - ); - const request = spec.buildRequests([bidRequest])[0]; - const payload = JSON.parse(request.data); - expect(payload.tags[0].hb_source).to.deep.equal(7); - }); - it('should contain hb_source value for other media', function() { const bidRequest = Object.assign({}, bidRequests[0], @@ -542,21 +363,6 @@ describe('MediaFuseAdapter', function () { expect(payload.tags[0].hb_source).to.deep.equal(1); }); - it('adds brand_category_exclusion to request when set', function() { - const bidRequest = Object.assign({}, bidRequests[0]); - sinon - .stub(config, 'getConfig') - .withArgs('adpod.brandCategoryExclusion') - .returns(true); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - - expect(payload.brand_category_uniqueness).to.equal(true); - - config.getConfig.restore(); - }); - it('adds auction level keywords to request when set', function() { const bidRequest = Object.assign({}, bidRequests[0]); sinon @@ -1261,46 +1067,6 @@ describe('MediaFuseAdapter', function () { expect(result[0]).to.have.property('mediaType', 'video'); }); - it('handles adpod responses', function () { - const response = { - 'tags': [{ - 'uuid': '84ab500420319d', - 'ads': [{ - 'ad_type': 'video', - 'brand_category_id': 10, - 'cpm': 0.500000, - 'notify_url': 'imptracker.com', - 'rtb': { - 'video': { - 'asset_url': 'https://sample.vastURL.com/here/adpod', - 'duration_ms': 30000, - } - }, - 'viewability': { - 'config': '' - } - }] - }] - }; - - const bidderRequest = { - bids: [{ - bidId: '84ab500420319d', - adUnitCode: 'code', - mediaTypes: { - video: { - context: 'adpod' - } - } - }] - }; - - const result = spec.interpretResponse({ body: response }, {bidderRequest}); - expect(result[0]).to.have.property('vastUrl'); - expect(result[0].video.context).to.equal('adpod'); - expect(result[0].video.durationSeconds).to.equal(30); - }); - it('handles native responses', function () { const response1 = deepClone(response); response1.tags[0].ads[0].ad_type = 'native'; @@ -1378,33 +1144,6 @@ describe('MediaFuseAdapter', function () { ); }); - it('should add deal_priority and deal_code', function() { - const responseWithDeal = deepClone(response); - responseWithDeal.tags[0].ads[0].ad_type = 'video'; - responseWithDeal.tags[0].ads[0].deal_priority = 5; - responseWithDeal.tags[0].ads[0].deal_code = '123'; - responseWithDeal.tags[0].ads[0].rtb.video = { - duration_ms: 1500, - player_width: 640, - player_height: 340, - }; - - const bidderRequest = { - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code', - mediaTypes: { - video: { - context: 'adpod' - } - } - }] - } - const result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest}); - expect(Object.keys(result[0].mediafuse)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']); - expect(result[0].video.dealTier).to.equal(5); - }); - it('should add advertiser id', function() { const responseAdvertiserId = deepClone(response); responseAdvertiserId.tags[0].ads[0].advertiser_id = '123'; diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index c3c14f3d0bb..728c68c20b1 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -2066,19 +2066,6 @@ describe('Media.net bid adapter', function () { expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_WITH_USERIDASEIDS); }); - it('should have valid payload when PAAPI is enabled', function () { - const bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, paapi: {enabled: true}}); - expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_PAAPI); - }); - - it('should send whatever is set in ortb2imp.ext.ae in all bid requests when PAAPI is enabled', function () { - const bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, paapi: {enabled: true}}); - const data = JSON.parse(bidReq.data); - expect(data).to.deep.equal(VALID_PAYLOAD_PAAPI); - expect(data.imp[0].ext).to.have.property('ae'); - expect(data.imp[0].ext.ae).to.equal(1); - }); - describe('build requests: when page meta-data is available', () => { beforeEach(() => { spec.clearPageMeta(); @@ -2254,32 +2241,6 @@ describe('Media.net bid adapter', function () { const bids = spec.interpretResponse(SERVER_RESPONSE_EMPTY_BIDLIST, []); expect(bids).to.deep.equal(validBids); }); - - it('should return paapi if PAAPI response is received', function() { - const response = spec.interpretResponse(SERVER_RESPONSE_PAAPI, []); - expect(response).to.have.property('bids'); - expect(response).to.have.property('paapi'); - expect(response.paapi[0]).to.deep.equal(SERVER_RESPONSE_PAAPI.body.ext.paApiAuctionConfigs[0]); - }); - - it('should return paapi if openRTB PAAPI response received', function () { - const response = spec.interpretResponse(SERVER_RESPONSE_PAAPI_ORTB, []); - expect(response).to.have.property('bids'); - expect(response).to.have.property('paapi'); - expect(response.paapi[0]).to.deep.equal(SERVER_RESPONSE_PAAPI_ORTB.body.ext.igi[0].igs[0]) - }); - - it('should have the correlation between paapi[0].bidId and bidreq.imp[0].id', function() { - const bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, paapi: {enabled: true}}); - const bidRes = spec.interpretResponse(SERVER_RESPONSE_PAAPI, []); - expect(bidRes.paapi[0].bidId).to.equal(JSON.parse(bidReq.data).imp[0].id) - }); - - it('should have the correlation between paapi[0].bidId and bidreq.imp[0].id for openRTB response', function() { - const bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, paapi: {enabled: true}}); - const bidRes = spec.interpretResponse(SERVER_RESPONSE_PAAPI_ORTB, []); - expect(bidRes.paapi[0].bidId).to.equal(JSON.parse(bidReq.data).imp[0].id) - }); }); describe('onTimeout', function () { diff --git a/test/spec/modules/mgidBidAdapter_spec.js b/test/spec/modules/mgidBidAdapter_spec.js index 3019cebe377..e6c5f752418 100644 --- a/test/spec/modules/mgidBidAdapter_spec.js +++ b/test/spec/modules/mgidBidAdapter_spec.js @@ -2,7 +2,6 @@ import {expect} from 'chai'; import { spec, storage } from 'modules/mgidBidAdapter.js'; import { version } from 'package.json'; import * as utils from '../../../src/utils.js'; -import { getDNT } from 'libraries/dnt/index.js'; import {USERSYNC_DEFAULT_CONFIG} from '../../../src/userSync.js'; import {config} from '../../../src/config.js'; @@ -23,7 +22,7 @@ describe('Mgid bid adapter', function () { }); const screenHeight = screen.height; const screenWidth = screen.width; - const dnt = getDNT() ? 1 : 0; + const dnt = 0; // DNT deprecated by W3C; Prebid no longer supports DNT const language = navigator.language ? 'language' : 'userLanguage'; let lang = navigator[language].split('-')[0]; if (lang.length !== 2 && lang.length !== 3) { diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index dd37a929b45..cda513fb1c2 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -768,38 +768,6 @@ describe('onetag', function () { expect(payload.ortb2).to.exist; expect(payload.ortb2).to.exist.and.to.deep.equal(dsa); }); - it('Should send FLEDGE eligibility flag when FLEDGE is enabled', function () { - const bidderRequest = { - 'bidderCode': 'onetag', - 'auctionId': '1d1a030790a475', - 'bidderRequestId': '22edbae2733bf6', - 'timeout': 3000, - 'paapi': { - 'enabled': true - } - }; - const serverRequest = spec.buildRequests([bannerBid], bidderRequest); - const payload = JSON.parse(serverRequest.data); - - expect(payload.fledgeEnabled).to.exist; - expect(payload.fledgeEnabled).to.exist.and.to.equal(bidderRequest.paapi.enabled); - }); - it('Should send FLEDGE eligibility flag when FLEDGE is not enabled', function () { - const bidderRequest = { - 'bidderCode': 'onetag', - 'auctionId': '1d1a030790a475', - 'bidderRequestId': '22edbae2733bf6', - 'timeout': 3000, - paapi: { - enabled: false - } - }; - const serverRequest = spec.buildRequests([bannerBid], bidderRequest); - const payload = JSON.parse(serverRequest.data); - - expect(payload.fledgeEnabled).to.exist; - expect(payload.fledgeEnabled).to.exist.and.to.equal(bidderRequest.paapi.enabled); - }); it('Should send FLEDGE eligibility flag set to false when fledgeEnabled is not defined', function () { const bidderRequest = { 'bidderCode': 'onetag', @@ -821,13 +789,7 @@ describe('onetag', function () { const requestData = JSON.parse(request.data); it('Returns an array of valid server responses if response object is valid', function () { const interpretedResponse = spec.interpretResponse(response, request); - const fledgeInterpretedResponse = spec.interpretResponse(fledgeResponse, request); expect(interpretedResponse).to.be.an('array').that.is.not.empty; - expect(fledgeInterpretedResponse).to.be.an('object'); - expect(fledgeInterpretedResponse.bids).to.satisfy(function (value) { - return value === null || Array.isArray(value); - }); - expect(fledgeInterpretedResponse.paapi).to.be.an('array').that.is.not.empty; for (let i = 0; i < interpretedResponse.length; i++) { const dataItem = interpretedResponse[i]; expect(dataItem).to.include.all.keys('requestId', 'cpm', 'width', 'height', 'ttl', 'creativeId', 'netRevenue', 'currency', 'meta', 'dealId'); diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index dfcdecdf586..a0b5e841f85 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -4,7 +4,6 @@ import {newBidder} from 'src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from 'src/mediaTypes.js'; import {config} from 'src/config.js'; import * as utils from 'src/utils.js'; -import * as dnt from 'libraries/dnt/index.js'; // load modules that register ORTB processors import 'src/prebid.js' import 'modules/currency.js'; @@ -13,7 +12,6 @@ import 'modules/multibid/index.js'; import 'modules/priceFloors.js'; import 'modules/consentManagementTcf.js'; import 'modules/consentManagementUsp.js'; -import 'modules/paapi.js'; import {deepClone} from 'src/utils.js'; import {version} from 'package.json'; @@ -1051,32 +1049,7 @@ describe('OpenxRtbAdapter', function () { }); context('do not track (DNT)', function() { - let doNotTrackStub; - - beforeEach(function () { - doNotTrackStub = sinon.stub(dnt, 'getDNT'); - }); - afterEach(function() { - doNotTrackStub.restore(); - }); - - it('when there is a do not track, should send a dnt', async function () { - doNotTrackStub.returns(1); - - const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); - expect(request[0].data.device.dnt).to.equal(1); - }); - - it('when there is not do not track, don\'t send dnt', async function () { - doNotTrackStub.returns(0); - - const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); - expect(request[0].data.device.dnt).to.equal(0); - }); - - it('when there is no defined do not track, don\'t send dnt', async function () { - doNotTrackStub.returns(null); - + it('always sends dnt as 0', async function () { const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(0); }); @@ -1226,18 +1199,6 @@ describe('OpenxRtbAdapter', function () { expect(request[0].data).to.not.have.any.keys('user'); }); }); - - context('FLEDGE', function() { - it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, { - ...mockBidderRequest, - paapi: { - enabled: true - } - }); - expect(request[0].data.imp[0].ext.ae).to.equal(2); - }); - }); }); context('banner', function () { @@ -1885,104 +1846,6 @@ describe('OpenxRtbAdapter', function () { }); }); } - - context('when the response contains FLEDGE interest groups config', function() { - let response; - - beforeEach(function () { - sinon.stub(config, 'getConfig') - .withArgs('fledgeEnabled') - .returns(true); - - bidRequestConfigs = [{ - bidder: 'openx', - params: { - unit: '12345678', - delDomain: 'test-del-domain' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]], - }, - }, - bidId: 'test-bid-id', - bidderRequestId: 'test-bidder-request-id', - auctionId: 'test-auction-id' - }]; - - bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0]; - - bidResponse = { - seatbid: [{ - bid: [{ - impid: 'test-bid-id', - price: 2, - w: 300, - h: 250, - crid: 'test-creative-id', - dealid: 'test-deal-id', - adm: 'test-ad-markup' - }] - }], - cur: 'AUS', - ext: { - fledge_auction_configs: { - 'test-bid-id': { - seller: 'codinginadtech.com', - interestGroupBuyers: ['somedomain.com'], - sellerTimeout: 0, - perBuyerSignals: { - 'somedomain.com': { - base_bid_micros: 0.1, - disallowed_advertiser_ids: [ - '1234', - '2345' - ], - multiplier: 1.3, - use_bid_multiplier: true, - win_reporting_id: '1234567asdf' - } - } - } - } - } - }; - - response = spec.interpretResponse({body: bidResponse}, bidRequest); - }); - - afterEach(function () { - config.getConfig.restore(); - }); - - it('should return FLEDGE auction_configs alongside bids', function () { - expect(response).to.have.property('bids'); - expect(response).to.have.property('paapi'); - expect(response.paapi.length).to.equal(1); - expect(response.paapi[0].bidId).to.equal('test-bid-id'); - }); - - it('should inject ortb2Imp in auctionSignals', function () { - const auctionConfig = response.paapi[0].config; - expect(auctionConfig).to.deep.include({ - auctionSignals: { - ortb2Imp: { - id: 'test-bid-id', - tagid: '12345678', - banner: { - topframe: 0, - format: bidRequestConfigs[0].mediaTypes.banner.sizes.map(([w, h]) => ({w, h})) - }, - ext: { - divid: 'adunit-code', - }, - secure: 1 - } - } - }); - }) - }); }); describe('user sync', function () { diff --git a/test/spec/modules/optableBidAdapter_spec.js b/test/spec/modules/optableBidAdapter_spec.js deleted file mode 100644 index b7cf2e3b44d..00000000000 --- a/test/spec/modules/optableBidAdapter_spec.js +++ /dev/null @@ -1,116 +0,0 @@ -import { expect } from 'chai'; -import { spec } from 'modules/optableBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory.js'; - -describe('optableBidAdapter', function() { - const adapter = newBidder(spec); - - describe('isBidRequestValid', function() { - const validBid = { - bidder: 'optable', - params: { site: '123' }, - }; - - it('should return true when required params are present', function() { - expect(spec.isBidRequestValid(validBid)).to.be.true; - }); - - it('should return false when site is missing', function() { - const invalidBid = { ...validBid }; - delete invalidBid.params.site; - expect(spec.isBidRequestValid(invalidBid)).to.be.false; - }); - }); - - describe('buildRequests', function() { - const validBid = { - bidder: 'optable', - params: { - site: '123', - }, - }; - - const bidderRequest = { - bidderRequestId: 'bid123', - refererInfo: { - domain: 'example.com', - page: 'https://example.com/page', - ref: 'https://referrer.com' - }, - }; - - it('should include site as tagid in imp', function() { - const request = spec.buildRequests([validBid], bidderRequest); - expect(request.url).to.equal('https://ads.optable.co/ca/ortb2/v1/ssp/bid'); - expect(request.method).to.equal('POST'); - expect(request.data.imp[0].tagid).to.equal('123') - }); - }); - - describe('buildPAAPIConfigs', () => { - function makeRequest({bidId, site = 'mockSite', ae = 1}) { - return { - bidId, - params: { - site - }, - ortb2Imp: { - ext: {ae} - } - } - } - it('should generate auction configs for ae requests', () => { - const configs = spec.buildPAAPIConfigs([ - makeRequest({bidId: 'bid1', ae: 1}), - makeRequest({bidId: 'bid2', ae: 0}), - makeRequest({bidId: 'bid3', ae: 1}), - ]); - expect(configs.map(cfg => cfg.bidId)).to.eql(['bid1', 'bid3']); - configs.forEach(cfg => sinon.assert.match(cfg.config, { - seller: 'https://ads.optable.co', - decisionLogicURL: `https://ads.optable.co/ca/paapi/v1/ssp/decision-logic.js?origin=mockSite`, - interestGroupBuyers: ['https://ads.optable.co'] - })) - }) - }) - - describe('interpretResponse', function() { - const validBid = { - bidder: 'optable', - params: { - site: '123', - }, - }; - - const bidderRequest = { - bidderRequestId: 'bid123', - refererInfo: { - domain: 'example.com', - page: 'https://example.com/page', - ref: 'https://referrer.com' - }, - }; - - const response = { - body: { - ext: { - optable: { - fledge: { - auctionconfigs: [ - { impid: 'bid123', seller: 'https://ads.optable.co' }, - ] - } - } - } - } - }; - - it('maps paapi from ext.optable.fledge.auctionconfigs', function() { - const request = spec.buildRequests([validBid], bidderRequest); - const result = spec.interpretResponse(response, request); - expect(result.paapi).to.deep.equal([ - { bidId: 'bid123', config: { seller: 'https://ads.optable.co' } } - ]); - }); - }); -}); diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js index 3eabc8a5190..16440f7e11d 100644 --- a/test/spec/modules/ozoneBidAdapter_spec.js +++ b/test/spec/modules/ozoneBidAdapter_spec.js @@ -3154,15 +3154,6 @@ describe('ozone Adapter', function () { const payload = JSON.parse(request.data); expect(payload.ext.ozone.cookieDeprecationLabel).to.equal('none'); }); - it('should handle fledge requests', function () { - const bidderRequest = JSON.parse(JSON.stringify(validBidderRequest)); - const bidRequests = JSON.parse(JSON.stringify(validBidRequests)); - deepSetValue(bidRequests[0], 'ortb2Imp.ext.ae', 1); - bidderRequest.fledgeEnabled = true; - const request = spec.buildRequests(bidRequests, bidderRequest); - const payload = JSON.parse(request.data); - expect(payload.imp[0].ext.ae).to.equal(1); - }); it('Single request: should use ortb auction ID & transaction ID values if set (this will be the case when publisher opts in with config)', function() { var specMock = utils.deepClone(spec); config.setConfig({'ozone': {'singleRequest': true}}); @@ -3424,20 +3415,6 @@ describe('ozone Adapter', function () { const bid = result[0]; expect(bid.mediaType).to.equal('video'); }); - it('should handle fledge response', function () { - const req = spec.buildRequests(validBidRequests, validBidderRequest); - const objResp = JSON.parse(JSON.stringify(validResponse)); - objResp.body.ext = {igi: [{ - 'impid': '1', - 'igb': [{ - 'origin': 'https://paapi.dsp.com', - 'pbs': '{"key": "value"}' - }] - }]}; - const result = spec.interpretResponse(objResp, req); - expect(result).to.be.an('object'); - expect(result.fledgeAuctionConfigs[0]['impid']).to.equal('1'); - }); it('should add labels in the adserver request if they are present in the auction response', function () { const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest); const validres = JSON.parse(JSON.stringify(validResponse2Bids)); diff --git a/test/spec/modules/paapiForGpt_spec.js b/test/spec/modules/paapiForGpt_spec.js deleted file mode 100644 index eb75d51540d..00000000000 --- a/test/spec/modules/paapiForGpt_spec.js +++ /dev/null @@ -1,216 +0,0 @@ -import { - getPAAPISizeHook, - onAuctionConfigFactory, - setPAAPIConfigFactory, setTargetingHookFactory, - slotConfigurator -} from 'modules/paapiForGpt.js'; -import * as gptUtils from '../../../libraries/gptUtils/gptUtils.js'; -import 'modules/appnexusBidAdapter.js'; -import 'modules/rubiconBidAdapter.js'; -import {deepSetValue} from '../../../src/utils.js'; -import {config} from 'src/config.js'; - -describe('paapiForGpt module', () => { - let sandbox, fledgeAuctionConfig; - - beforeEach(() => { - sandbox = sinon.createSandbox(); - fledgeAuctionConfig = { - seller: 'bidder', - mock: 'config' - }; - }); - afterEach(() => { - sandbox.restore(); - }); - - describe('slotConfigurator', () => { - let setGptConfig; - function mockGptSlot(auPath) { - return { - setConfig: sinon.stub(), - getAdUnitPath: () => auPath - } - } - beforeEach(() => { - setGptConfig = slotConfigurator(); - }); - - Object.entries({ - 'single slot': [mockGptSlot('mock/gpt/au')], - 'multiple slots': [mockGptSlot('mock/gpt/au'), mockGptSlot('mock/gpt/au2')] - }).forEach(([t, gptSlots]) => { - describe(`when ad unit code matches ${t}`, () => { - it('should set GPT slot config', () => { - setGptConfig('au', gptSlots, [fledgeAuctionConfig]); - gptSlots.forEach(slot => { - sinon.assert.calledWith(slot.setConfig, { - componentAuction: [{ - configKey: 'bidder', - auctionConfig: fledgeAuctionConfig, - }] - }); - }) - }); - describe('when reset = true', () => { - it('should reset GPT slot config', () => { - setGptConfig('au', gptSlots, [fledgeAuctionConfig]); - gptSlots.forEach(slot => slot.setConfig.resetHistory()); - setGptConfig('au', gptSlots, [], true); - gptSlots.forEach(slot => { - sinon.assert.calledWith(slot.setConfig, { - componentAuction: [{ - configKey: 'bidder', - auctionConfig: null - }] - }); - }) - }); - - it('should reset only sellers with no fresh config', () => { - setGptConfig('au', gptSlots, [{seller: 's1'}, {seller: 's2'}]); - gptSlots.forEach(slot => slot.setConfig.resetHistory()); - setGptConfig('au', gptSlots, [{seller: 's1'}], true); - gptSlots.forEach(slot => { - sinon.assert.calledWith(slot.setConfig, { - componentAuction: [{ - configKey: 's1', - auctionConfig: {seller: 's1'} - }, { - configKey: 's2', - auctionConfig: null - }] - }) - }) - }); - - it('should not reset sellers that were already reset', () => { - setGptConfig('au', gptSlots, [{seller: 's1'}]); - setGptConfig('au', gptSlots, [], true); - gptSlots.forEach(slot => slot.setConfig.resetHistory()); - setGptConfig('au', gptSlots, [], true); - gptSlots.forEach(slot => sinon.assert.notCalled(slot.setConfig)); - }) - - it('should keep track of configuration history by ad unit', () => { - setGptConfig('au1', gptSlots, [{seller: 's1'}]); - setGptConfig('au1', gptSlots, [{seller: 's2'}], false); - setGptConfig('au2', gptSlots, [{seller: 's3'}]); - gptSlots.forEach(slot => slot.setConfig.resetHistory()); - setGptConfig('au1', gptSlots, [], true); - gptSlots.forEach(slot => { - sinon.assert.calledWith(slot.setConfig, { - componentAuction: [{ - configKey: 's1', - auctionConfig: null - }, { - configKey: 's2', - auctionConfig: null - }] - }); - }) - }) - }); - }) - }) - }); - describe('setTargeting hook', () => { - let setPaapiConfig, setTargetingHook, next; - beforeEach(() => { - setPaapiConfig = sinon.stub() - setTargetingHook = setTargetingHookFactory(setPaapiConfig); - next = sinon.stub(); - }); - function expectFilters(...filters) { - expect(setPaapiConfig.args.length).to.eql(filters.length) - filters.forEach(filter => { - sinon.assert.calledWith(setPaapiConfig, filter, 'mock-matcher') - }) - } - function runHook(adUnit) { - setTargetingHook(next, adUnit, 'mock-matcher'); - sinon.assert.calledWith(next, adUnit, 'mock-matcher'); - } - it('should invoke with no filters when adUnit is undef', () => { - runHook(); - expectFilters(undefined); - }); - it('should invoke once when adUnit is a string', () => { - runHook('mock-au'); - expectFilters({adUnitCode: 'mock-au'}) - }); - it('should invoke once per ad unit when an array', () => { - runHook(['au1', 'au2']); - expectFilters({adUnitCode: 'au1'}, {adUnitCode: 'au2'}); - }) - }) - describe('setPAAPIConfigForGpt', () => { - let getPAAPIConfig, setGptConfig, getSlots, setPAAPIConfigForGPT; - beforeEach(() => { - getPAAPIConfig = sinon.stub(); - setGptConfig = sinon.stub(); - getSlots = sinon.stub().callsFake((codes) => Object.fromEntries(codes.map(code => [code, ['mock-slot']]))) - setPAAPIConfigForGPT = setPAAPIConfigFactory(getPAAPIConfig, setGptConfig, getSlots); - }); - - Object.entries({ - missing: null, - empty: {} - }).forEach(([t, configs]) => { - it(`does not set GPT slot config when config is ${t}`, () => { - getPAAPIConfig.returns(configs); - setPAAPIConfigForGPT('mock-filters'); - sinon.assert.calledWith(getPAAPIConfig, 'mock-filters'); - sinon.assert.notCalled(setGptConfig); - }) - }); - - it('passes customSlotMatching to getSlots', () => { - getPAAPIConfig.returns({au1: {}}); - setPAAPIConfigForGPT('mock-filters', 'mock-custom-matching'); - sinon.assert.calledWith(getSlots, ['au1'], 'mock-custom-matching'); - }) - - it('sets GPT slot config for each ad unit that has PAAPI config, and resets the rest', () => { - const cfg = { - au1: { - componentAuctions: [{seller: 's1'}, {seller: 's2'}] - }, - au2: { - componentAuctions: [{seller: 's3'}] - }, - au3: null - } - getPAAPIConfig.returns(cfg); - setPAAPIConfigForGPT('mock-filters'); - sinon.assert.calledWith(getPAAPIConfig, 'mock-filters'); - Object.entries(cfg).forEach(([au, config]) => { - sinon.assert.calledWith(setGptConfig, au, ['mock-slot'], config?.componentAuctions ?? [], true); - }) - }); - }); - - describe('getPAAPISizeHook', () => { - let next; - beforeEach(() => { - next = sinon.stub(); - next.bail = sinon.stub(); - }); - - it('should pick largest supported size over larger unsupported size', () => { - getPAAPISizeHook(next, [[999, 999], [300, 250], [300, 600], [1234, 4321]]); - sinon.assert.calledWith(next.bail, [300, 600]); - }); - - Object.entries({ - 'present': [], - 'supported': [[123, 4], [321, 5]], - 'defined': undefined, - }).forEach(([t, sizes]) => { - it(`should defer to next when no size is ${t}`, () => { - getPAAPISizeHook(next, sizes); - sinon.assert.calledWith(next, sizes); - }) - }) - }) -}); diff --git a/test/spec/modules/paapi_spec.js b/test/spec/modules/paapi_spec.js deleted file mode 100644 index 2d491cdfe14..00000000000 --- a/test/spec/modules/paapi_spec.js +++ /dev/null @@ -1,2014 +0,0 @@ -import {expect} from 'chai'; -import {config} from '../../../src/config.js'; -import adapterManager from '../../../src/adapterManager.js'; -import * as utils from '../../../src/utils.js'; -import {deepAccess, deepClone} from '../../../src/utils.js'; -import {hook} from '../../../src/hook.js'; -import 'modules/appnexusBidAdapter.js'; -import 'modules/rubiconBidAdapter.js'; -import { - adAuctionHeadersHook, - addPaapiConfigHook, - addPaapiData, - ASYNC_SIGNALS, AsyncPAAPIParam, buildPAAPIParams, - buyersToAuctionConfigs, - getPAAPIConfig, - getPAAPISize, - IGB_TO_CONFIG, - mergeBuyers, NAVIGATOR_APIS, - onAuctionInit, - parallelPaapiProcessing, - parseExtIgi, - parseExtPrebidFledge, - partitionBuyers, - partitionBuyersByBidder, - registerSubmodule, - reset, - setImpExtAe, - setResponsePaapiConfigs -} from 'modules/paapi.js'; -import * as events from 'src/events.js'; -import {EVENTS} from 'src/constants.js'; -import {getGlobal} from '../../../src/prebidGlobal.js'; -import {auctionManager} from '../../../src/auctionManager.js'; -import {stubAuctionIndex} from '../../helpers/indexStub.js'; -import {AuctionIndex} from '../../../src/auctionIndex.js'; -import {buildActivityParams} from '../../../src/activities/params.js'; - -describe('paapi module', () => { - let sandbox; - before(reset); - beforeEach(() => { - sandbox = sinon.createSandbox(); - }); - afterEach(() => { - sandbox.restore(); - reset(); - }); - - describe(`using paapi configuration`, () => { - let getPAAPISizeStub; - - function getPAAPISizeHook(next, sizes) { - next.bail(getPAAPISizeStub(sizes)); - } - - before(() => { - getPAAPISize.before(getPAAPISizeHook, 100); - }); - - after(() => { - getPAAPISize.getHooks({hook: getPAAPISizeHook}).remove(); - }); - - beforeEach(() => { - getPAAPISizeStub = sinon.stub(); - }); - - describe('adAuctionHeadersHook', () => { - let bidderRequest, ajax; - beforeEach(() => { - ajax = sinon.stub(); - bidderRequest = {paapi: {}} - }) - function getWrappedAjax() { - let wrappedAjax; - const next = sinon.stub().callsFake((spec, bids, br, ajax) => { - wrappedAjax = ajax; - }); - adAuctionHeadersHook(next, {}, [], bidderRequest, ajax); - return wrappedAjax; - } - describe('when PAAPI is enabled', () => { - beforeEach(() => { - bidderRequest.paapi.enabled = true; - }); - [ - undefined, - {}, - {adAuctionHeaders: true} - ].forEach(options => - it(`should set adAuctionHeaders = true (when options are ${JSON.stringify(options)})`, () => { - getWrappedAjax()('url', {}, 'data', options); - sinon.assert.calledWith(ajax, 'url', {}, 'data', sinon.match({adAuctionHeaders: true})); - })); - - it('should respect adAuctionHeaders: false', () => { - getWrappedAjax()('url', {}, 'data', {adAuctionHeaders: false}); - sinon.assert.calledWith(ajax, 'url', {}, 'data', sinon.match({adAuctionHeaders: false})); - }) - }); - it('should not alter ajax when paapi is not enabled', () => { - expect(getWrappedAjax()).to.equal(ajax); - }) - }) - - describe('getPAAPIConfig', function () { - let nextFnSpy, auctionConfig, paapiConfig; - before(() => { - config.setConfig({paapi: {enabled: true}}); - }); - beforeEach(() => { - auctionConfig = { - seller: 'bidder', - mock: 'config' - }; - paapiConfig = { - config: auctionConfig - }; - nextFnSpy = sinon.spy(); - }); - - describe('on a single auction', function () { - const auctionId = 'aid'; - beforeEach(function () { - sandbox.stub(auctionManager, 'index').value(stubAuctionIndex({auctionId})); - }); - - it('should call next()', function () { - const request = {auctionId, adUnitCode: 'auc'}; - addPaapiConfigHook(nextFnSpy, request, paapiConfig); - sinon.assert.calledWith(nextFnSpy, request, paapiConfig); - }); - - describe('igb', () => { - let igb1, igb2, buyerAuctionConfig; - beforeEach(() => { - igb1 = { - origin: 'buyer.1' - }; - igb2 = { - origin: 'buyer.2' - }; - buyerAuctionConfig = { - seller: 'seller', - decisionLogicURL: 'seller-decision-logic' - }; - config.mergeConfig({ - paapi: { - componentSeller: { - auctionConfig: buyerAuctionConfig - } - } - }); - }); - - function addIgb(request, igb) { - addPaapiConfigHook(nextFnSpy, Object.assign({auctionId}, request), {igb}); - } - - it('should be collected into an auction config', () => { - addIgb({adUnitCode: 'au1'}, igb1); - addIgb({adUnitCode: 'au1'}, igb2); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']}); - const buyerConfig = getPAAPIConfig({auctionId}).au1.componentAuctions[0]; - sinon.assert.match(buyerConfig, { - interestGroupBuyers: [igb1.origin, igb2.origin], - ...buyerAuctionConfig - }); - }); - - describe('FPD', () => { - let ortb2, ortb2Imp; - beforeEach(() => { - ortb2 = {'fpd': 1}; - ortb2Imp = {'fpd': 2}; - }); - - function getBuyerAuctionConfig() { - addIgb({adUnitCode: 'au1', ortb2, ortb2Imp}, igb1); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']}); - return getPAAPIConfig({auctionId}).au1.componentAuctions[0]; - } - - it('should be added to auction config', () => { - sinon.assert.match(getBuyerAuctionConfig().perBuyerSignals[igb1.origin], { - prebid: { - ortb2, - ortb2Imp - } - }); - }); - - it('should not override existing perBuyerSignals', () => { - const original = { - ortb2: { - fpd: 'original' - } - }; - igb1.pbs = { - prebid: deepClone(original) - }; - sinon.assert.match(getBuyerAuctionConfig().perBuyerSignals[igb1.origin], { - prebid: original - }); - }); - }); - }); - - describe('should collect auction configs', () => { - let cf1, cf2; - beforeEach(() => { - cf1 = {...auctionConfig, id: 1, seller: 'b1'}; - cf2 = {...auctionConfig, id: 2, seller: 'b2'}; - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, {config: cf1}); - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, {config: cf2}); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']}); - }); - - it('and make them available at end of auction', () => { - sinon.assert.match(getPAAPIConfig({auctionId}), { - au1: { - componentAuctions: [cf1] - }, - au2: { - componentAuctions: [cf2] - } - }); - }); - - it('and filter them by ad unit', () => { - const cfg = getPAAPIConfig({auctionId, adUnitCode: 'au1'}); - expect(Object.keys(cfg)).to.have.members(['au1']); - sinon.assert.match(cfg.au1, { - componentAuctions: [cf1] - }); - }); - - it('and not return them again', () => { - getPAAPIConfig(); - const cfg = getPAAPIConfig(); - expect(cfg).to.eql({}); - }); - - describe('includeBlanks = true', () => { - it('includes all ad units', () => { - const cfg = getPAAPIConfig({}, true); - expect(Object.keys(cfg)).to.have.members(['au1', 'au2', 'au3']); - expect(cfg.au3).to.eql(null); - }); - it('includes the targeted adUnit', () => { - expect(getPAAPIConfig({adUnitCode: 'au3'}, true)).to.eql({ - au3: null - }); - }); - it('includes the targeted auction', () => { - const cfg = getPAAPIConfig({auctionId}, true); - expect(Object.keys(cfg)).to.have.members(['au1', 'au2', 'au3']); - expect(cfg.au3).to.eql(null); - }); - it('does not include non-existing ad units', () => { - expect(getPAAPIConfig({adUnitCode: 'other'})).to.eql({}); - }); - it('does not include non-existing auctions', () => { - expect(getPAAPIConfig({auctionId: 'other'})).to.eql({}); - }); - }); - }); - - it('should drop auction configs after end of auction', () => { - events.emit(EVENTS.AUCTION_END, {auctionId}); - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, paapiConfig); - expect(getPAAPIConfig({auctionId})).to.eql({}); - }); - - describe('FPD', () => { - let ortb2, ortb2Imp; - beforeEach(() => { - ortb2 = {fpd: 1}; - ortb2Imp = {fpd: 2}; - }); - - function getComponentAuctionConfig() { - addPaapiConfigHook(nextFnSpy, { - auctionId, - adUnitCode: 'au1', - ortb2: {fpd: 1}, - ortb2Imp: {fpd: 2} - }, paapiConfig); - events.emit(EVENTS.AUCTION_END, {auctionId}); - return getPAAPIConfig({auctionId}).au1.componentAuctions[0]; - } - - it('should be added to auctionSignals', () => { - sinon.assert.match(getComponentAuctionConfig().auctionSignals, { - prebid: {ortb2, ortb2Imp} - }); - }); - it('should not override existing auctionSignals', () => { - auctionConfig.auctionSignals = {prebid: {ortb2: {fpd: 'original'}}}; - sinon.assert.match(getComponentAuctionConfig().auctionSignals, { - prebid: { - ortb2: {fpd: 'original'}, - ortb2Imp - } - }); - }); - - it('should be added to perBuyerSignals', () => { - auctionConfig.interestGroupBuyers = ['buyer.1', 'buyer.2']; - const pbs = getComponentAuctionConfig().perBuyerSignals; - sinon.assert.match(pbs, { - 'buyer.1': {prebid: {ortb2, ortb2Imp}}, - 'buyer.2': {prebid: {ortb2, ortb2Imp}} - }); - }); - - it('should not override existing perBuyerSignals', () => { - auctionConfig.interestGroupBuyers = ['buyer']; - const original = { - prebid: { - ortb2: { - fpd: 'original' - } - } - }; - auctionConfig.perBuyerSignals = { - buyer: deepClone(original) - }; - sinon.assert.match(getComponentAuctionConfig().perBuyerSignals.buyer, original); - }); - }); - - describe('submodules', () => { - let submods; - beforeEach(() => { - submods = [1, 2].map(i => ({ - name: `test${i}`, - onAuctionConfig: sinon.stub() - })); - submods.forEach(registerSubmodule); - }); - - describe('onAuctionConfig', () => { - const auctionId = 'aid'; - it('is invoked with null configs when there\'s no config', () => { - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au']}); - submods.forEach(submod => sinon.assert.calledWith(submod.onAuctionConfig, auctionId, {au: null})); - }); - it('is invoked with relevant configs', () => { - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, paapiConfig); - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, paapiConfig); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']}); - submods.forEach(submod => { - sinon.assert.calledWith(submod.onAuctionConfig, auctionId, { - au1: {componentAuctions: [auctionConfig]}, - au2: {componentAuctions: [auctionConfig]}, - au3: null - }); - }); - }); - }); - }); - - describe('floor signal', () => { - before(() => { - if (!getGlobal().convertCurrency) { - getGlobal().convertCurrency = () => null; - getGlobal().convertCurrency.mock = true; - } - }); - after(() => { - if (getGlobal().convertCurrency.mock) { - delete getGlobal().convertCurrency; - } - }); - - beforeEach(() => { - sandbox.stub(getGlobal(), 'convertCurrency').callsFake((amount, from, to) => { - if (from === to) return amount; - if (from === 'USD' && to === 'JPY') return amount * 100; - if (from === 'JPY' && to === 'USD') return amount / 100; - throw new Error('unexpected currency conversion'); - }); - }); - - Object.entries({ - 'bids': (payload, values) => { - payload.bidsReceived = values - .map((val) => ({adUnitCode: 'au', cpm: val.amount, currency: val.cur})) - .concat([{adUnitCode: 'other', cpm: 10000, currency: 'EUR'}]); - }, - 'no bids': (payload, values) => { - payload.bidderRequests = values - .map((val) => ({ - bids: [{ - adUnitCode: 'au', - getFloor: () => ({floor: val.amount, currency: val.cur}) - }] - })) - .concat([{bids: {adUnitCode: 'other', getFloor: () => ({floor: -10000, currency: 'EUR'})}}]); - } - }).forEach(([tcase, setup]) => { - describe(`when auction has ${tcase}`, () => { - Object.entries({ - 'no currencies': { - values: [{amount: 1}, {amount: 100}, {amount: 10}, {amount: 100}], - 'bids': { - bidfloor: 100, - bidfloorcur: undefined - }, - 'no bids': { - bidfloor: 1, - bidfloorcur: undefined, - } - }, - 'only zero values': { - values: [{amount: 0, cur: 'USD'}, {amount: 0, cur: 'JPY'}], - 'bids': { - bidfloor: undefined, - bidfloorcur: undefined, - }, - 'no bids': { - bidfloor: undefined, - bidfloorcur: undefined, - } - }, - 'matching currencies': { - values: [{amount: 10, cur: 'JPY'}, {amount: 100, cur: 'JPY'}], - 'bids': { - bidfloor: 100, - bidfloorcur: 'JPY', - }, - 'no bids': { - bidfloor: 10, - bidfloorcur: 'JPY', - } - }, - 'mixed currencies': { - values: [{amount: 10, cur: 'USD'}, {amount: 10, cur: 'JPY'}], - 'bids': { - bidfloor: 10, - bidfloorcur: 'USD' - }, - 'no bids': { - bidfloor: 10, - bidfloorcur: 'JPY', - } - } - }).forEach(([t, testConfig]) => { - const values = testConfig.values; - const {bidfloor, bidfloorcur} = testConfig[tcase]; - - describe(`with ${t}`, () => { - let payload; - beforeEach(() => { - payload = {auctionId}; - setup(payload, values); - }); - - it('should populate bidfloor/bidfloorcur', () => { - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, paapiConfig); - events.emit(EVENTS.AUCTION_END, payload); - const cfg = getPAAPIConfig({auctionId}).au; - const signals = cfg.auctionSignals; - sinon.assert.match(cfg.componentAuctions[0].auctionSignals, signals || {}); - expect(signals?.prebid?.bidfloor).to.eql(bidfloor); - expect(signals?.prebid?.bidfloorcur).to.eql(bidfloorcur); - }); - }); - }); - }); - }); - }); - - describe('requestedSize', () => { - let adUnit; - beforeEach(() => { - adUnit = { - code: 'au', - }; - }); - - function getConfig() { - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode: adUnit.code}, paapiConfig); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: [adUnit.code], adUnits: [adUnit]}); - return getPAAPIConfig()[adUnit.code]; - } - - Object.entries({ - 'adUnit.ortb2Imp.ext.paapi.requestedSize'() { - adUnit.ortb2Imp = { - ext: { - paapi: { - requestedSize: { - width: 123, - height: 321 - } - } - } - }; - }, - 'largest size'() { - getPAAPISizeStub.returns([123, 321]); - } - }).forEach(([t, setup]) => { - describe(`should be set from ${t}`, () => { - beforeEach(setup); - - it('without overriding component auctions, if set', () => { - auctionConfig.requestedSize = {width: '1px', height: '2px'}; - expect(getConfig().componentAuctions[0].requestedSize).to.eql({ - width: '1px', - height: '2px' - }); - }); - - it('on component auction, if missing', () => { - expect(getConfig().componentAuctions[0].requestedSize).to.eql({ - width: 123, - height: 321 - }); - }); - - it('on top level auction', () => { - expect(getConfig().requestedSize).to.eql({ - width: 123, - height: 321, - }); - }); - }); - }); - }); - }); - - describe('with multiple auctions', () => { - const AUCTION1 = 'auction1'; - const AUCTION2 = 'auction2'; - - function mockAuction(auctionId) { - return { - getAuctionId() { - return auctionId; - } - }; - } - - function expectAdUnitsFromAuctions(actualConfig, auToAuctionMap) { - expect(Object.keys(actualConfig)).to.have.members(Object.keys(auToAuctionMap)); - Object.entries(actualConfig).forEach(([au, cfg]) => { - cfg.componentAuctions.forEach(cmp => expect(cmp.auctionId).to.eql(auToAuctionMap[au])); - }); - } - - let configs; - beforeEach(() => { - const mockAuctions = [mockAuction(AUCTION1), mockAuction(AUCTION2)]; - sandbox.stub(auctionManager, 'index').value(new AuctionIndex(() => mockAuctions)); - configs = {[AUCTION1]: {}, [AUCTION2]: {}}; - Object.entries({ - [AUCTION1]: [['au1', 'au2'], ['missing-1']], - [AUCTION2]: [['au2', 'au3'], []], - }).forEach(([auctionId, [adUnitCodes, noConfigAdUnitCodes]]) => { - adUnitCodes.forEach(adUnitCode => { - const cfg = {...auctionConfig, auctionId, adUnitCode}; - configs[auctionId][adUnitCode] = cfg; - addPaapiConfigHook(nextFnSpy, {auctionId, adUnitCode}, {config: cfg}); - }); - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: adUnitCodes.concat(noConfigAdUnitCodes)}); - }); - }); - - it('should filter by auction', () => { - expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1}), {au1: AUCTION1, au2: AUCTION1}); - expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION2}), {au2: AUCTION2, au3: AUCTION2}); - }); - - it('should filter by auction and ad unit', () => { - expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1, adUnitCode: 'au2'}), {au2: AUCTION1}); - expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION2, adUnitCode: 'au2'}), {au2: AUCTION2}); - }); - - it('should use last auction for each ad unit', () => { - expectAdUnitsFromAuctions(getPAAPIConfig(), {au1: AUCTION1, au2: AUCTION2, au3: AUCTION2}); - }); - - it('should filter by ad unit and use latest auction', () => { - expectAdUnitsFromAuctions(getPAAPIConfig({adUnitCode: 'au2'}), {au2: AUCTION2}); - }); - - it('should keep track of which configs were returned', () => { - expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1}), {au1: AUCTION1, au2: AUCTION1}); - expect(getPAAPIConfig({auctionId: AUCTION1})).to.eql({}); - expectAdUnitsFromAuctions(getPAAPIConfig(), {au2: AUCTION2, au3: AUCTION2}); - }); - - describe('includeBlanks = true', () => { - Object.entries({ - 'auction with blanks': { - filters: {auctionId: AUCTION1}, - expected: {au1: true, au2: true, 'missing-1': false} - }, - 'blank adUnit in an auction': { - filters: {auctionId: AUCTION1, adUnitCode: 'missing-1'}, - expected: {'missing-1': false} - }, - 'non-existing auction': { - filters: {auctionId: 'other'}, - expected: {} - }, - 'non-existing adUnit in an auction': { - filters: {auctionId: AUCTION2, adUnitCode: 'other'}, - expected: {} - }, - 'non-existing ad unit': { - filters: {adUnitCode: 'other'}, - expected: {}, - }, - 'non existing ad unit in a non-existing auction': { - filters: {adUnitCode: 'other', auctionId: 'other'}, - expected: {} - }, - 'all ad units': { - filters: {}, - expected: {'au1': true, 'au2': true, 'missing-1': false, 'au3': true} - } - }).forEach(([t, {filters, expected}]) => { - it(t, () => { - const cfg = getPAAPIConfig(filters, true); - expect(Object.keys(cfg)).to.have.members(Object.keys(expected)); - Object.entries(expected).forEach(([au, shouldBeFilled]) => { - if (shouldBeFilled) { - expect(cfg[au]).to.not.be.null; - } else { - expect(cfg[au]).to.be.null; - } - }); - }); - }); - }); - }); - }); - - describe('markForFledge', function () { - const navProps = Object.fromEntries(['runAdAuction', 'joinAdInterestGroup'].map(p => [p, navigator[p]])); - let adUnits; - - before(function () { - // navigator.runAdAuction & co may not exist, so we can't stub it normally with - // sinon.stub(navigator, 'runAdAuction') or something - Object.keys(navProps).forEach(p => { - navigator[p] = sinon.stub(); - }); - hook.ready(); - config.resetConfig(); - }); - - after(function () { - Object.entries(navProps).forEach(([p, orig]) => navigator[p] = orig); - }); - - beforeEach(() => { - getPAAPISizeStub = sinon.stub(); - adUnits = [{ - 'code': '/19968336/header-bid-tag1', - 'mediaTypes': { - 'banner': { - 'sizes': [[728, 90]] - }, - }, - 'bids': [ - { - 'bidder': 'appnexus', - }, - { - 'bidder': 'rubicon', - }, - ] - }]; - }); - - afterEach(function () { - config.resetConfig(); - }); - - describe('makeBidRequests', () => { - before(() => { - NAVIGATOR_APIS.forEach(method => { - if (navigator[method] == null) { - navigator[method] = () => null; - after(() => { - delete navigator[method]; - }) - } - }) - }); - beforeEach(() => { - NAVIGATOR_APIS.forEach(method => { - sandbox.stub(navigator, method) - }) - }); - - function mark() { - return Object.fromEntries( - adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() { - }, - [] - ).map(b => [b.bidderCode, b]) - ); - } - - async function testAsyncParams(bidderRequest) { - for (const method of NAVIGATOR_APIS) { - navigator[method].returns('result'); - expect(await bidderRequest.paapi[method]('arg').resolve()).to.eql('result'); - sinon.assert.calledWith(navigator[method], 'arg'); - } - } - - async function expectFledgeFlags(...enableFlags) { - const bidRequests = mark(); - expect(bidRequests.appnexus.paapi?.enabled).to.eql(enableFlags[0].enabled); - if (bidRequests.appnexus.paapi?.enabled) { - await testAsyncParams(bidRequests.appnexus) - } - bidRequests.appnexus.bids.forEach(bid => expect(bid.ortb2Imp.ext.ae).to.eql(enableFlags[0].ae)); - - expect(bidRequests.rubicon.paapi?.enabled).to.eql(enableFlags[1].enabled); - if (bidRequests.rubicon.paapi?.enabled) { - testAsyncParams(bidRequests.rubicon); - } - - bidRequests.rubicon.bids.forEach(bid => expect(bid.ortb2Imp?.ext?.ae).to.eql(enableFlags[1].ae)); - - Object.values(bidRequests).flatMap(req => req.bids).forEach(bid => { - if (bid.ortb2Imp?.ext?.ae) { - sinon.assert.match(bid.ortb2Imp.ext.igs, { - ae: bid.ortb2Imp.ext.ae, - biddable: 1 - }); - } - }); - } - - describe('with setConfig()', () => { - it('should set paapi.enabled correctly per bidder', async function () { - config.setConfig({ - bidderSequence: 'fixed', - paapi: { - enabled: true, - bidders: ['appnexus'], - defaultForSlots: 1, - } - }); - await expectFledgeFlags({enabled: true, ae: 1}, {enabled: false, ae: 0}); - }); - - it('should set paapi.enabled correctly for all bidders', async function () { - config.setConfig({ - bidderSequence: 'fixed', - paapi: { - enabled: true, - defaultForSlots: 1, - } - }); - await expectFledgeFlags({enabled: true, ae: 1}, {enabled: true, ae: 1}); - }); - - Object.entries({ - 'not set': { - cfg: {}, - componentSeller: false - }, - 'set': { - cfg: { - componentSeller: { - auctionConfig: { - decisionLogicURL: 'publisher.example' - } - } - }, - componentSeller: true - } - }).forEach(([t, {cfg, componentSeller}]) => { - it(`should set request paapi.componentSeller = ${componentSeller} when config componentSeller is ${t}`, () => { - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1, - ...cfg - } - }); - Object.values(mark()).forEach(br => expect(br.paapi?.componentSeller).to.eql(componentSeller)); - }); - }); - }); - }); - describe('addPaapiData', () => { - function getEnrichedAdUnits() { - const next = sinon.stub(); - addPaapiData(next, adUnits); - sinon.assert.calledWith(next, adUnits); - return adUnits; - } - - function getImpExt() { - const next = sinon.stub(); - addPaapiData(next, adUnits); - sinon.assert.calledWith(next, adUnits); - return { - global: adUnits[0].ortb2Imp?.ext, - ...Object.fromEntries(adUnits[0].bids.map(bid => [bid.bidder, bid.ortb2Imp?.ext])) - } - } - - it('should not override pub-defined ext.ae', () => { - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1, - } - }); - Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 0}}}); - sinon.assert.match(getImpExt(), { - global: { - ae: 0, - }, - rubicon: undefined, - appnexus: undefined - }); - }); - - it('should override per-bidder when excluded via paapi.bidders', () => { - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1, - bidders: ['rubicon'] - } - }) - sinon.assert.match(getImpExt(), { - global: { - ae: 1, - igs: { - ae: 1, - biddable: 1 - } - }, - rubicon: undefined, - appnexus: { - ae: 0, - igs: { - ae: 0, - biddable: 0 - } - } - }) - }) - - it('should populate ext.igs when request has ext.ae', () => { - config.setConfig({ - paapi: { - enabled: true - } - }); - Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 3}}}); - sinon.assert.match(getImpExt(), { - global: { - ae: 3, - igs: { - ae: 3, - biddable: 1 - } - }, - rubicon: undefined, - appnexus: undefined, - }); - }); - - it('should not override pub-defined ext.igs', () => { - config.setConfig({ - paapi: { - enabled: true - } - }); - Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 1, igs: {biddable: 0}}}}); - sinon.assert.match(getImpExt(), { - global: { - ae: 1, - igs: { - ae: 1, - biddable: 0 - } - }, - rubicon: undefined, - appnexus: undefined - }) - }); - - it('should fill ext.ae from ext.igs, if defined', () => { - config.setConfig({ - paapi: { - enabled: true - } - }); - Object.assign(adUnits[0], {ortb2Imp: {ext: {igs: {}}}}); - sinon.assert.match(getImpExt(), { - global: { - ae: 1, - igs: { - ae: 1, - biddable: 1 - } - }, - appnexus: undefined, - rubicon: undefined - }) - }); - - describe('ortb2Imp.ext.paapi.requestedSize', () => { - beforeEach(() => { - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1, - } - }); - }); - - it('should default to value returned by getPAAPISize', () => { - getPAAPISizeStub.returns([123, 321]); - expect(getImpExt().global.paapi).to.eql({ - requestedSize: { - width: 123, - height: 321 - } - }); - }); - - it('should not be overridden, if provided by the pub', () => { - adUnits[0].ortb2Imp = { - ext: { - paapi: { - requestedSize: { - width: '123px', - height: '321px' - } - } - } - }; - expect(getImpExt().global.paapi).to.eql({ - requestedSize: { - width: '123px', - height: '321px' - } - }) - sinon.assert.notCalled(getPAAPISizeStub); - }); - - it('should not be set if adUnit has no banner sizes', () => { - adUnits[0].mediaTypes = { - video: {} - }; - expect(getImpExt().global?.paapi?.requestedSize).to.not.exist; - }); - }); - }); - }); - }); - - describe('igb', () => { - let igb1, igb2; - const buyer1 = 'https://buyer1.example'; - const buyer2 = 'https://buyer2.example'; - beforeEach(() => { - igb1 = { - origin: buyer1, - cur: 'EUR', - maxbid: 1, - pbs: { - signal: 1 - }, - ps: { - priority: 1 - } - }; - igb2 = { - origin: buyer2, - cur: 'USD', - maxbid: 2, - pbs: { - signal: 2 - }, - ps: { - priority: 2 - } - }; - }); - - describe('mergeBuyers', () => { - it('should merge multiple igb into a partial auction config', () => { - sinon.assert.match(mergeBuyers([igb1, igb2]), { - interestGroupBuyers: [buyer1, buyer2], - perBuyerCurrencies: { - [buyer1]: 'EUR', - [buyer2]: 'USD' - }, - perBuyerSignals: { - [buyer1]: { - signal: 1 - }, - [buyer2]: { - signal: 2 - } - }, - perBuyerPrioritySignals: { - [buyer1]: { - priority: 1 - }, - [buyer2]: { - priority: 2 - } - }, - auctionSignals: { - prebid: { - perBuyerMaxbid: { - [buyer1]: 1, - [buyer2]: 2 - } - } - } - }); - }); - - Object.entries(IGB_TO_CONFIG).forEach(([igbField, configField]) => { - it(`should not set ${configField} if ${igbField} is undefined`, () => { - delete igb1[igbField]; - expect(deepAccess(mergeBuyers([igb1, igb2]), configField)[buyer1]).to.not.exist; - }); - }); - - it('ignores igbs that have no origin', () => { - delete igb1.origin; - expect(mergeBuyers([igb1, igb2])).to.eql(mergeBuyers([igb2])); - }); - - it('ignores igbs with duplicate origin', () => { - igb2.origin = igb1.origin; - expect(mergeBuyers([igb1, igb2])).to.eql(mergeBuyers([igb1])); - }); - }); - - describe('partitionBuyers', () => { - it('should return a single partition when there are no duplicates', () => { - expect(partitionBuyers([igb1, igb2])).to.eql([[igb1, igb2]]); - }); - it('should ignore igbs that have no origin', () => { - delete igb1.origin; - expect(partitionBuyers([igb1, igb2])).to.eql([[igb2]]); - }); - it('should return a single partition when duplicates exist, but do not conflict', () => { - expect(partitionBuyers([igb1, igb2, deepClone(igb1)])).to.eql([[igb1, igb2]]); - }); - it('should return multiple partitions when there are conflicts', () => { - const igb3 = deepClone(igb1); - const igb4 = deepClone(igb1); - igb3.pbs.signal = 'conflict'; - igb4.ps.signal = 'conflict'; - expect(partitionBuyers([igb1, igb2, igb3, igb4])).to.eql([ - [igb1, igb2], - [igb3], - [igb4] - ]); - }); - }); - - describe('partitionBuyersByBidder', () => { - it('should split requests by bidder', () => { - expect(partitionBuyersByBidder([[{bidder: 'a'}, igb1], [{bidder: 'b'}, igb2]])).to.eql([ - [{bidder: 'a'}, [igb1]], - [{bidder: 'b'}, [igb2]] - ]); - }); - - it('accepts repeated buyers, if from different bidders', () => { - expect(partitionBuyersByBidder([ - [{bidder: 'a', extra: 'data'}, igb1], - [{bidder: 'b', more: 'data'}, igb1], - [{bidder: 'a'}, igb2], - [{bidder: 'b'}, igb2] - ])).to.eql([ - [{bidder: 'a', extra: 'data'}, [igb1, igb2]], - [{bidder: 'b', more: 'data'}, [igb1, igb2]] - ]); - }); - describe('buyersToAuctionConfig', () => { - let config, partitioners, merge, igbRequests; - beforeEach(() => { - config = { - auctionConfig: { - decisionLogicURL: 'mock-decision-logic' - } - }; - partitioners = { - compact: sinon.stub(), - expand: sinon.stub(), - }; - let i = 0; - merge = sinon.stub().callsFake(() => ({config: i++})); - igbRequests = [ - [{}, igb1], - [{}, igb2] - ]; - }); - - function toAuctionConfig(reqs = igbRequests) { - return buyersToAuctionConfigs(reqs, merge, config, partitioners); - } - - it('uses compact partitions by default, and returns an auction config for each one', () => { - partitioners.compact.returns([[{}, 1], [{}, 2]]); - const [cf1, cf2] = toAuctionConfig(); - sinon.assert.match(cf1[1], { - ...config.auctionConfig, - config: 0 - }); - sinon.assert.match(cf2[1], { - ...config.auctionConfig, - config: 1 - }); - sinon.assert.calledWith(partitioners.compact, igbRequests); - [1, 2].forEach(mockPart => sinon.assert.calledWith(merge, mockPart)); - }); - - it('uses per-bidder partition when config has separateAuctions', () => { - config.separateAuctions = true; - partitioners.expand.returns([]); - toAuctionConfig(); - sinon.assert.called(partitioners.expand); - }); - - it('does not return any auction config when configuration does not specify auctionConfig', () => { - delete config.auctionConfig; - expect(toAuctionConfig()).to.eql([]); - Object.values(partitioners).forEach(part => sinon.assert.notCalled(part)); - }); - - it('sets FPD in auction signals when partitioner returns it', () => { - const fpd = { - ortb2: {fpd: 1}, - ortb2Imp: {fpd: 2} - }; - partitioners.compact.returns([[{}], [fpd]]); - const [cf1, cf2] = toAuctionConfig(); - expect(cf1[1].auctionSignals?.prebid).to.not.exist; - expect(cf2[1].auctionSignals.prebid).to.eql(fpd); - }); - }); - }); - }); - - describe('getPAAPISize', () => { - before(() => { - getPAAPISize.getHooks().remove(); - }); - - Object.entries({ - 'ignores placeholders': { - in: [[1, 1], [0, 0], [3, 4]], - out: [3, 4] - }, - 'picks largest size by area': { - in: [[200, 100], [150, 150]], - out: [150, 150] - }, - 'can handle no sizes': { - in: [], - out: undefined - }, - 'can handle no input': { - in: undefined, - out: undefined - }, - 'can handle placeholder sizes': { - in: [[1, 1]], - out: undefined - } - }).forEach(([t, {in: input, out}]) => { - it(t, () => { - expect(getPAAPISize(input)).to.eql(out); - }); - }); - }); - - describe('buildPaapiParameters', () => { - let next, bidderRequest, spec, bids; - beforeEach(() => { - next = sinon.stub(); - spec = {}; - bidderRequest = {paapi: {enabled: true}}; - bids = []; - }); - - function runParamHook() { - return Promise.resolve(buildPAAPIParams(next, spec, bids, bidderRequest)); - } - - Object.entries({ - 'has no paapiParameters': () => null, - 'returns empty parameter map'() { - spec.paapiParameters = () => ({}) - }, - 'returns null parameter map'() { - spec.paapiParameters = () => null - }, - 'returns params, but PAAPI is disabled'() { - bidderRequest.paapi.enabled = false; - spec.paapiParameters = () => ({param: new AsyncPAAPIParam()}) - } - }).forEach(([t, setup]) => { - it(`should do nothing if spec ${t}`, async () => { - setup(); - await runParamHook(); - sinon.assert.calledWith(next, spec, bids, bidderRequest); - }) - }) - - describe('when paapiParameters returns a map', () => { - let params; - beforeEach(() => { - spec.paapiParameters = sinon.stub().callsFake(() => params); - }); - it('should be invoked with bids & bidderRequest', async () => { - await runParamHook(); - sinon.assert.calledWith(spec.paapiParameters, bids, bidderRequest); - }); - it('should leave most things (including promises) untouched', async () => { - params = { - 'p1': 'scalar', - 'p2': Promise.resolve() - } - await runParamHook(); - expect(bidderRequest.paapi.params).to.eql(params); - }); - it('should resolve async PAAPI parameeters', async () => { - params = { - 'resolved': new AsyncPAAPIParam(() => Promise.resolve('value')), - } - await runParamHook(); - expect(bidderRequest.paapi.params).to.eql({ - 'resolved': 'value' - }) - }) - - it('should still call next if the resolution fails', async () => { - params = { - error: new AsyncPAAPIParam(() => Promise.reject(new Error())) - } - await runParamHook(); - sinon.assert.called(next); - expect(bidderRequest.paapi.params).to.not.exist; - }) - }) - }) - - describe('parallel PAAPI auctions', () => { - describe('parallellPaapiProcessing', () => { - let next, spec, bids, bidderRequest, restOfTheArgs, mockConfig, mockAuction, bidsReceived, bidderRequests, adUnitCodes, adUnits; - - beforeEach(() => { - next = sinon.stub(); - spec = { - code: 'mockBidder', - }; - bids = [{ - bidder: 'mockBidder', - bidId: 'bidId', - adUnitCode: 'au', - auctionId: 'aid', - ortb2: { - source: { - tid: 'aid' - }, - }, - mediaTypes: { - banner: { - sizes: [[123, 321]] - } - } - }]; - bidderRequest = { - auctionId: 'aid', - bidderCode: 'mockBidder', - paapi: {enabled: true}, - bids, - ortb2: { - source: { - tid: 'aid' - } - } - }; - restOfTheArgs = [{more: 'args'}]; - mockConfig = { - seller: 'mock.seller', - decisionLogicURL: 'mock.seller/decisionLogic', - interestGroupBuyers: ['mock.buyer'] - } - mockAuction = {}; - bidsReceived = [{adUnitCode: 'au', cpm: 1}]; - adUnits = [{code: 'au'}] - adUnitCodes = ['au']; - bidderRequests = [bidderRequest]; - sandbox.stub(auctionManager.index, 'getAuction').callsFake(() => mockAuction); - sandbox.stub(auctionManager.index, 'getAdUnit').callsFake((req) => bids.find(bid => bid.adUnitCode === req.adUnitCode)) - config.setConfig({paapi: {enabled: true}}); - }); - - afterEach(() => { - sinon.assert.calledWith(next, spec, bids, bidderRequest, ...restOfTheArgs); - config.resetConfig(); - }); - - function startParallel() { - parallelPaapiProcessing(next, spec, bids, bidderRequest, ...restOfTheArgs); - onAuctionInit({auctionId: 'aid'}) - } - - function endAuction() { - events.emit(EVENTS.AUCTION_END, {auctionId: 'aid', bidsReceived, bidderRequests, adUnitCodes, adUnits}) - } - - describe('should have no effect when', () => { - afterEach(() => { - expect(getPAAPIConfig({}, true)).to.eql({au: null}); - }) - it('spec has no buildPAAPIConfigs', () => { - startParallel(); - }); - Object.entries({ - 'returns no configs': () => { spec.buildPAAPIConfigs = sinon.stub().callsFake(() => []); }, - 'throws': () => { spec.buildPAAPIConfigs = sinon.stub().callsFake(() => { throw new Error() }) }, - 'returns too little config': () => { spec.buildPAAPIConfigs = sinon.stub().callsFake(() => [ {bidId: 'bidId', config: {seller: 'mock.seller'}} ]) }, - 'bidder is not paapi enabled': () => { - bidderRequest.paapi.enabled = false; - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => [{config: mockConfig, bidId: 'bidId'}]) - }, - 'paapi module is not enabled': () => { - delete bidderRequest.paapi; - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => [{config: mockConfig, bidId: 'bidId'}]) - }, - 'bidId points to missing bid': () => { spec.buildPAAPIConfigs = sinon.stub().callsFake(() => [{config: mockConfig, bidId: 'missing'}]) } - }).forEach(([t, setup]) => { - it(`buildPAAPIConfigs ${t}`, () => { - setup(); - startParallel(); - }); - }); - }); - - function resolveConfig(auctionConfig) { - return Promise.all( - Object.entries(auctionConfig) - .map(([key, value]) => Promise.resolve(value).then(value => [key, value])) - ).then(result => Object.fromEntries(result)) - } - - describe('when buildPAAPIConfigs returns valid config', () => { - let builtCfg; - beforeEach(() => { - builtCfg = [{bidId: 'bidId', config: mockConfig}]; - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => builtCfg); - }); - - it('should make async config available from getPAAPIConfig', () => { - startParallel(); - const actual = getPAAPIConfig(); - const promises = Object.fromEntries(ASYNC_SIGNALS.map(signal => [signal, sinon.match((arg) => arg instanceof Promise)])) - sinon.assert.match(actual, { - au: sinon.match({ - ...promises, - requestedSize: { - width: 123, - height: 321 - }, - componentAuctions: [ - sinon.match({ - ...mockConfig, - ...promises, - requestedSize: { - width: 123, - height: 321 - } - }) - ] - }) - }); - }); - - it('should work when called multiple times for the same auction', () => { - startParallel(); - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => []); - startParallel(); - expect(getPAAPIConfig().au.componentAuctions.length).to.eql(1); - }); - - it('should hide TIDs from buildPAAPIConfigs', () => { - config.setConfig({enableTIDs: false}); - startParallel(); - sinon.assert.calledWith( - spec.buildPAAPIConfigs, - sinon.match(bidRequests => bidRequests.every(req => req.auctionId == null)), - sinon.match(bidderRequest => bidderRequest.auctionId == null) - ); - }); - - it('should show TIDs when enabled', () => { - config.setConfig({enableTIDs: true}); - startParallel(); - sinon.assert.calledWith( - spec.buildPAAPIConfigs, - sinon.match(bidRequests => bidRequests.every(req => req.auctionId === 'aid')), - sinon.match(bidderRequest => bidderRequest.auctionId === 'aid') - ) - }) - - it('should respect requestedSize from adapter', () => { - mockConfig.requestedSize = {width: 1, height: 2}; - startParallel(); - sinon.assert.match(getPAAPIConfig().au, { - requestedSize: { - width: 123, - height: 321 - }, - componentAuctions: [sinon.match({ - requestedSize: { - width: 1, - height: 2 - } - })] - }) - }) - - it('should not accept multiple partial configs for the same bid/seller', () => { - builtCfg.push(builtCfg[0]) - startParallel(); - expect(getPAAPIConfig().au.componentAuctions.length).to.eql(1); - }); - it('should resolve top level config with auction signals', async () => { - startParallel(); - let config = getPAAPIConfig().au; - endAuction(); - config = await resolveConfig(config); - sinon.assert.match(config, { - auctionSignals: { - prebid: {bidfloor: 1} - } - }) - }); - - describe('when adapter returns the rest of auction config', () => { - let configRemainder; - beforeEach(() => { - configRemainder = { - ...Object.fromEntries(ASYNC_SIGNALS.map(signal => [signal, {type: signal}])), - seller: 'mock.seller' - }; - }) - function returnRemainder() { - addPaapiConfigHook(sinon.stub(), bids[0], {config: configRemainder}); - } - it('should resolve component configs with values returned by adapters', async () => { - startParallel(); - let config = getPAAPIConfig().au.componentAuctions[0]; - returnRemainder(); - endAuction(); - config = await resolveConfig(config); - sinon.assert.match(config, configRemainder); - }); - - it('should pick first config that matches bidId/seller', async () => { - startParallel(); - let config = getPAAPIConfig().au.componentAuctions[0]; - returnRemainder(); - const expectedSignals = {...configRemainder}; - configRemainder = { - ...configRemainder, - auctionSignals: { - this: 'should be ignored' - } - } - returnRemainder(); - endAuction(); - config = await resolveConfig(config); - sinon.assert.match(config, expectedSignals); - }); - - describe('should default to values returned from buildPAAPIConfigs when interpretResponse does not return', () => { - beforeEach(() => { - ASYNC_SIGNALS.forEach(signal => mockConfig[signal] = {default: signal}) - }); - Object.entries({ - 'returns no matching config'() { - }, - 'does not include values in response'() { - configRemainder = {}; - returnRemainder(); - } - }).forEach(([t, postResponse]) => { - it(t, async () => { - startParallel(); - let config = getPAAPIConfig().au.componentAuctions[0]; - postResponse(); - endAuction(); - config = await resolveConfig(config); - sinon.assert.match(config, mockConfig); - }); - }); - }); - - it('should resolve to undefined when no value is available', async () => { - startParallel(); - let config = getPAAPIConfig().au.componentAuctions[0]; - delete configRemainder.sellerSignals; - returnRemainder(); - endAuction(); - config = await resolveConfig(config); - expect(config.sellerSignals).to.be.undefined; - }); - - [ - { - start: {t: 'scalar', value: 'str'}, - end: {t: 'array', value: ['abc']}, - should: {t: 'array', value: ['abc']} - }, - { - start: {t: 'object', value: {a: 'b'}}, - end: {t: 'scalar', value: 'abc'}, - should: {t: 'scalar', value: 'abc'} - }, - { - start: {t: 'object', value: {outer: {inner: 'val'}}}, - end: {t: 'object', value: {outer: {other: 'val'}}}, - should: {t: 'merge', value: {outer: {inner: 'val', other: 'val'}}} - } - ].forEach(({start, end, should}) => { - it(`when buildPAAPIConfigs returns ${start.t}, interpretResponse return ${end.t}, promise should resolve to ${should.t}`, async () => { - mockConfig.sellerSignals = start.value - startParallel(); - let config = getPAAPIConfig().au.componentAuctions[0]; - configRemainder.sellerSignals = end.value; - returnRemainder(); - endAuction(); - config = await resolveConfig(config); - expect(config.sellerSignals).to.eql(should.value); - }) - }) - - it('should make extra configs available', async () => { - startParallel(); - returnRemainder(); - configRemainder = {...configRemainder, seller: 'other.seller'}; - returnRemainder(); - endAuction(); - let configs = getPAAPIConfig().au.componentAuctions; - configs = [await resolveConfig(configs[0]), configs[1]]; - expect(configs.map(cfg => cfg.seller)).to.eql(['mock.seller', 'other.seller']); - }); - - describe('submodule\'s onAuctionConfig', () => { - let onAuctionConfig; - beforeEach(() => { - onAuctionConfig = sinon.stub(); - registerSubmodule({onAuctionConfig}) - }); - - Object.entries({ - 'parallel=true, some configs deferred': { - setup() { - config.mergeConfig({paapi: {parallel: true}}) - }, - delayed: false, - }, - 'parallel=true, no deferred configs': { - setup() { - config.mergeConfig({paapi: {parallel: true}}); - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => []); - }, - delayed: true - }, - 'parallel=false, some configs deferred': { - setup() { - config.mergeConfig({paapi: {parallel: false}}) - }, - delayed: true - } - }).forEach(([t, {setup, delayed}]) => { - describe(`when ${t}`, () => { - beforeEach(() => { - mockAuction.requestsDone = Promise.resolve(); - setup(); - }); - - function expectInvoked(shouldBeInvoked) { - if (shouldBeInvoked) { - sinon.assert.calledWith(onAuctionConfig, 'aid', sinon.match(arg => arg.au.componentAuctions[0].seller === 'mock.seller')); - } else { - sinon.assert.notCalled(onAuctionConfig); - } - } - - it(`should invoke onAuctionConfig when ${delayed ? 'auction ends' : 'auction requests have started'}`, async () => { - startParallel(); - await mockAuction.requestsDone; - expectInvoked(!delayed); - onAuctionConfig.resetHistory(); - returnRemainder(); - endAuction(); - expectInvoked(delayed); - }) - }) - }) - }) - }); - }); - describe('when buildPAAPIConfigs returns igb', () => { - let builtCfg, igb, auctionConfig; - beforeEach(() => { - igb = {origin: 'mock.buyer'} - builtCfg = [{bidId: 'bidId', igb}]; - spec.buildPAAPIConfigs = sinon.stub().callsFake(() => builtCfg); - auctionConfig = { - seller: 'mock.seller', - decisionLogicUrl: 'mock.seller/decisionLogic' - } - config.mergeConfig({ - paapi: { - componentSeller: { - auctionConfig - } - } - }) - bidderRequest.paapi.componentSeller = true; - }); - Object.entries({ - 'componentSeller not configured'() { - bidderRequest.paapi.componentSeller = false; - }, - 'buildPAAPIconfig returns nothing'() { - builtCfg = [] - }, - 'returned igb is not valid'() { - builtCfg = [{bidId: 'bidId', igb: {}}]; - } - }).forEach(([t, setup]) => { - it(`should have no effect when ${t}`, () => { - setup(); - startParallel(); - expect(getPAAPIConfig()).to.eql({}); - }) - }) - - describe('when component seller is set up', () => { - it('should generate a deferred auctionConfig', () => { - startParallel(); - sinon.assert.match(getPAAPIConfig().au.componentAuctions[0], { - ...auctionConfig, - interestGroupBuyers: ['mock.buyer'], - }) - }); - - it('should use signal values from componentSeller.auctionConfig', async () => { - auctionConfig.auctionSignals = {test: 'signal'}; - config.mergeConfig({ - paapi: {componentSeller: {auctionConfig}} - }) - startParallel(); - endAuction(); - const cfg = await resolveConfig(getPAAPIConfig().au.componentAuctions[0]); - sinon.assert.match(cfg.auctionSignals, auctionConfig.auctionSignals); - }) - - it('should collate buyers', () => { - startParallel(); - startParallel(); - sinon.assert.match(getPAAPIConfig().au.componentAuctions[0], { - interestGroupBuyers: ['mock.buyer'] - }); - }); - - function returnIgb(igb) { - addPaapiConfigHook(sinon.stub(), bids[0], {igb}); - } - - it('should resolve to values from interpretResponse as well as buildPAAPIConfigs', async () => { - igb.cur = 'cur'; - igb.pbs = {over: 'ridden'} - startParallel(); - let cfg = getPAAPIConfig().au.componentAuctions[0]; - returnIgb({ - origin: 'mock.buyer', - pbs: {some: 'signal'} - }); - endAuction(); - cfg = await resolveConfig(cfg); - sinon.assert.match(cfg, { - perBuyerSignals: { - [igb.origin]: {some: 'signal'}, - }, - perBuyerCurrencies: { - [igb.origin]: 'cur' - } - }) - }); - - it('should not overwrite config once resolved', () => { - startParallel(); - returnIgb({ - origin: 'mock.buyer', - }); - endAuction(); - const cfg = getPAAPIConfig().au; - sinon.assert.match(cfg, Object.fromEntries(ASYNC_SIGNALS.map(signal => [signal, sinon.match(arg => arg instanceof Promise)]))) - }) - - it('can resolve multiple igbs', async () => { - igb.cur = 'cur1'; - startParallel(); - spec.code = 'other'; - igb.origin = 'other.buyer' - igb.cur = 'cur2' - startParallel(); - let cfg = getPAAPIConfig().au.componentAuctions[0]; - returnIgb({ - origin: 'mock.buyer', - pbs: {signal: 1} - }); - returnIgb({ - origin: 'other.buyer', - pbs: {signal: 2} - }); - endAuction(); - cfg = await resolveConfig(cfg); - sinon.assert.match(cfg, { - perBuyerSignals: { - 'mock.buyer': {signal: 1}, - 'other.buyer': {signal: 2} - }, - perBuyerCurrencies: { - 'mock.buyer': 'cur1', - 'other.buyer': 'cur2' - } - }) - }) - - function startMultiple() { - startParallel(); - spec.code = 'other'; - igb.origin = 'other.buyer' - startParallel(); - } - - describe('when using separateAuctions=false', () => { - beforeEach(() => { - config.mergeConfig({ - paapi: { - componentSeller: { - separateAuctions: false - } - } - }) - }); - - it('should merge igb from different specs into a single auction config', () => { - startMultiple(); - sinon.assert.match(getPAAPIConfig().au.componentAuctions[0], { - interestGroupBuyers: ['mock.buyer', 'other.buyer'] - }); - }); - }) - - describe('when using separateAuctions=true', () => { - beforeEach(() => { - config.mergeConfig({ - paapi: { - componentSeller: { - separateAuctions: true - } - } - }) - }); - it('should generate an auction config for each bidder', () => { - startMultiple(); - const components = getPAAPIConfig().au.componentAuctions; - sinon.assert.match(components[0], { - interestGroupBuyers: ['mock.buyer'] - }) - sinon.assert.match(components[1], { - interestGroupBuyers: ['other.buyer'] - }) - }) - }) - }) - }) - }); - }); - - describe('ortb processors for fledge', () => { - it('imp.ext.ae should be removed if fledge is not enabled', () => { - const imp = {ext: {ae: 1, igs: {}}}; - setImpExtAe(imp, {}, {bidderRequest: {}}); - expect(imp.ext.ae).to.not.exist; - expect(imp.ext.igs).to.not.exist; - }); - it('imp.ext.ae should be left intact if fledge is enabled', () => { - const imp = {ext: {ae: 2, igs: {biddable: 0}}}; - setImpExtAe(imp, {}, {bidderRequest: {paapi: {enabled: true}}}); - expect(imp.ext).to.eql({ - ae: 2, - igs: { - biddable: 0 - } - }); - }); - - describe('response parsing', () => { - function generateImpCtx(fledgeFlags) { - return Object.fromEntries(Object.entries(fledgeFlags).map(([impid, fledgeEnabled]) => [impid, {imp: {ext: {ae: fledgeEnabled}}}])); - } - - function extractResult(type, ctx) { - return Object.fromEntries( - Object.entries(ctx) - .map(([impid, ctx]) => [impid, ctx.paapiConfigs?.map(cfg => cfg[type].id)]) - .filter(([_, val]) => val != null) - ); - } - - Object.entries({ - 'parseExtPrebidFledge': { - parser: parseExtPrebidFledge, - responses: { - 'ext.prebid.fledge'(configs) { - return { - ext: { - prebid: { - fledge: { - auctionconfigs: configs - } - } - } - }; - }, - } - }, - 'parseExtIgi': { - parser: parseExtIgi, - responses: { - 'ext.igi.igs'(configs) { - return { - ext: { - igi: [{ - igs: configs - }] - } - }; - }, - 'ext.igi.igs with impid on igi'(configs) { - return { - ext: { - igi: configs.map(cfg => { - const impid = cfg.impid; - delete cfg.impid; - return { - impid, - igs: [cfg] - }; - }) - } - }; - }, - 'ext.igi.igs with conflicting impid'(configs) { - return { - ext: { - igi: [{ - impid: 'conflict', - igs: configs - }] - } - }; - } - } - } - }).forEach(([t, {parser, responses}]) => { - describe(t, () => { - Object.entries(responses).forEach(([t, packageConfigs]) => { - describe(`when response uses ${t}`, () => { - function generateCfg(impid, ...ids) { - return ids.map((id) => ({impid, config: {id}})); - } - - it('should collect auction configs by imp', () => { - const ctx = { - impContext: generateImpCtx({e1: 1, e2: 1, d1: 0}) - }; - const resp = packageConfigs( - generateCfg('e1', 1, 2, 3) - .concat(generateCfg('e2', 4) - .concat(generateCfg('d1', 5, 6))) - ); - parser({}, resp, ctx); - expect(extractResult('config', ctx.impContext)).to.eql({ - e1: [1, 2, 3], - e2: [4], - }); - }); - it('should not choke if fledge config references unknown imp', () => { - const ctx = {impContext: generateImpCtx({i: 1})}; - const resp = packageConfigs(generateCfg('unknown', 1)); - parser({}, resp, ctx); - expect(extractResult('config', ctx.impContext)).to.eql({}); - }); - }); - }); - }); - }); - - describe('response ext.igi.igb', () => { - it('should collect igb by imp', () => { - const ctx = { - impContext: generateImpCtx({e1: 1, e2: 1, d1: 0}) - }; - const resp = { - ext: { - igi: [ - { - impid: 'e1', - igb: [ - {id: 1}, - {id: 2} - ] - }, - { - impid: 'e2', - igb: [ - {id: 3} - ] - }, - { - impid: 'd1', - igb: [ - {id: 4} - ] - } - ] - } - }; - parseExtIgi({}, resp, ctx); - expect(extractResult('igb', ctx.impContext)).to.eql({ - e1: [1, 2], - e2: [3], - }); - }); - }); - }); - - describe('setResponsePaapiConfigs', () => { - it('should set paapi configs/igb paired with their corresponding bid id', () => { - const ctx = { - impContext: { - 1: { - bidRequest: {bidId: 'bid1'}, - paapiConfigs: [{config: {id: 1}}, {config: {id: 2}}] - }, - 2: { - bidRequest: {bidId: 'bid2'}, - paapiConfigs: [{config: {id: 3}}] - }, - 3: { - bidRequest: {bidId: 'bid3'} - }, - 4: { - bidRequest: {bidId: 'bid1'}, - paapiConfigs: [{igb: {id: 4}}] - } - } - }; - const resp = {}; - setResponsePaapiConfigs(resp, {}, ctx); - expect(resp.paapi).to.eql([ - {bidId: 'bid1', config: {id: 1}}, - {bidId: 'bid1', config: {id: 2}}, - {bidId: 'bid2', config: {id: 3}}, - {bidId: 'bid1', igb: {id: 4}} - ]); - }); - it('should not set paapi if no config or igb exists', () => { - const resp = {}; - setResponsePaapiConfigs(resp, {}, { - impContext: { - 1: { - paapiConfigs: [] - }, - 2: {} - } - }); - expect(resp).to.eql({}); - }); - }); - }); -}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 595b95c6db8..025ac9592b2 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -23,17 +23,15 @@ import 'modules/priceFloors.js'; import 'modules/consentManagementTcf.js'; import 'modules/consentManagementUsp.js'; import 'modules/consentManagementGpp.js'; -import 'modules/paapi.js'; import * as redactor from 'src/activities/redactor.js'; import * as activityRules from 'src/activities/rules.js'; import {hook} from '../../../src/hook.js'; import {decorateAdUnitsWithNativeParams} from '../../../src/native.js'; import {auctionManager} from '../../../src/auctionManager.js'; import {stubAuctionIndex} from '../../helpers/indexStub.js'; -import {addPaapiConfig, registerBidder} from 'src/adapters/bidderFactory.js'; +import {registerBidder} from 'src/adapters/bidderFactory.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; import {addFPDToBidderRequest} from '../../helpers/fpd.js'; -import {deepSetValue} from '../../../src/utils.js'; import {ACTIVITY_TRANSMIT_UFPD} from '../../../src/activities/activities.js'; import {MODULE_TYPE_PREBID} from '../../../src/activities/modules.js'; import { @@ -3313,23 +3311,6 @@ describe('S2S Adapter', function () { expect(response).to.have.property('ttl', 60); }); - it('handles seatnonbid responses and emits SEAT_NON_BID', function () { - const original = CONFIG; - CONFIG.extPrebid = { returnallbidstatus: true }; - const nonbidResponse = {...RESPONSE_OPENRTB, ext: {seatnonbid: [{}]}}; - config.setConfig({ CONFIG }); - CONFIG = original; - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - const responding = deepClone(nonbidResponse); - Object.assign(responding.ext.seatnonbid, [{auctionId: 2}]) - server.requests[0].respond(200, {}, JSON.stringify(responding)); - const event = events.emit.thirdCall.args; - expect(event[0]).to.equal(EVENTS.SEAT_NON_BID); - expect(event[1].seatnonbid[0]).to.have.property('auctionId', 2); - expect(event[1].requestedBidders).to.deep.equal(['appnexus']); - expect(event[1].response).to.deep.equal(responding); - }); - it('emits the PBS_ANALYTICS event and captures seatnonbid responses', function () { const original = CONFIG; CONFIG.extPrebid = { returnallbidstatus: true }; @@ -3340,7 +3321,7 @@ describe('S2S Adapter', function () { const responding = deepClone(nonbidResponse); Object.assign(responding.ext.seatnonbid, [{auctionId: 2}]) server.requests[0].respond(200, {}, JSON.stringify(responding)); - const event = events.emit.getCall(3).args; + const event = events.emit.getCall(2).args; expect(event[0]).to.equal(EVENTS.PBS_ANALYTICS); expect(event[1].seatnonbid[0]).to.have.property('auctionId', 2); expect(event[1].requestedBidders).to.deep.equal(['appnexus']); @@ -3734,108 +3715,6 @@ describe('S2S Adapter', function () { }); }); }); - describe('when the response contains ext.prebid.fledge', () => { - const AU = 'div-gpt-ad-1460505748561-0'; - const FLEDGE_RESP = { - ext: { - prebid: { - fledge: { - auctionconfigs: [ - { - impid: AU, - bidder: 'appnexus', - config: { - id: 1 - } - }, - { - impid: AU, - bidder: 'other', - config: { - id: 2 - } - } - ] - } - } - } - } - - let fledgeStub, request, bidderRequests; - - function fledgeHook(next, ...args) { - fledgeStub(...args); - } - - before(() => { - addPaapiConfig.before(fledgeHook); - }); - - after(() => { - addPaapiConfig.getHooks({hook: fledgeHook}).remove(); - }) - - beforeEach(function () { - fledgeStub = sinon.stub(); - config.setConfig({ - s2sConfig: CONFIG, - }); - bidderRequests = deepClone(BID_REQUESTS); - bidderRequests.forEach(req => { - Object.assign(req, { - paapi: { - enabled: true - }, - ortb2: { - fpd: 1 - } - }) - req.bids.forEach(bid => { - Object.assign(bid, { - ortb2Imp: { - fpd: 2, - } - }) - }) - }); - request = deepClone(REQUEST); - request.ad_units.forEach(au => deepSetValue(au, 'ortb2Imp.ext.ae', 1)); - }); - - function expectFledgeCalls() { - const auctionId = bidderRequests[0].auctionId; - sinon.assert.calledWith(fledgeStub, sinon.match({auctionId, adUnitCode: AU, ortb2: bidderRequests[0].ortb2, ortb2Imp: bidderRequests[0].bids[0].ortb2Imp}), sinon.match({config: {id: 1}})) - sinon.assert.calledWith(fledgeStub, sinon.match({auctionId, adUnitCode: AU, ortb2: undefined, ortb2Imp: undefined}), sinon.match({config: {id: 2}})) - } - - it('calls addPaapiConfig alongside addBidResponse', function () { - adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); - server.requests[0].respond(200, {}, JSON.stringify(mergeDeep({}, RESPONSE_OPENRTB, FLEDGE_RESP))); - expect(addBidResponse.called).to.be.true; - expectFledgeCalls(); - }); - - it('calls addPaapiConfig when there is no bid in the response', () => { - adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); - server.requests[0].respond(200, {}, JSON.stringify(FLEDGE_RESP)); - expect(addBidResponse.called).to.be.false; - expectFledgeCalls(); - }); - - it('wraps call in runWithBidder', () => { - let fail = false; - fledgeStub.callsFake(({bidder}) => { - try { - expect(bidder).to.exist.and.to.eql(config.getCurrentBidder()); - } catch (e) { - fail = true; - } - }); - adapter.callBids(request, bidderRequests, addBidResponse, done, ajax); - server.requests[0].respond(200, {}, JSON.stringify(FLEDGE_RESP)); - expect(fail).to.be.false; - }) - }); }); describe('bid won events', function () { diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js deleted file mode 100644 index dbf6b2c9ef4..00000000000 --- a/test/spec/modules/quantcastBidAdapter_spec.js +++ /dev/null @@ -1,859 +0,0 @@ -import { expect } from 'chai'; -import { - QUANTCAST_DOMAIN, - QUANTCAST_TEST_DOMAIN, - QUANTCAST_NET_REVENUE, - QUANTCAST_TTL, - QUANTCAST_TEST_PUBLISHER, - QUANTCAST_PROTOCOL, - QUANTCAST_PORT, - spec as qcSpec, - storage -} from '../../../modules/quantcastBidAdapter.js'; -import { newBidder } from '../../../src/adapters/bidderFactory.js'; -import { parseUrl } from 'src/utils.js'; -import { config } from 'src/config.js'; -import {getGlobal} from '../../../src/prebidGlobal.js'; - -describe('Quantcast adapter', function () { - const quantcastAdapter = newBidder(qcSpec); - let bidRequest; - let bidderRequest; - - afterEach(function () { - getGlobal().bidderSettings = {}; - }); - beforeEach(function () { - getGlobal().bidderSettings = { - quantcast: { - storageAllowed: true - } - }; - bidRequest = { - bidder: 'quantcast', - bidId: '2f7b179d443f14', - auctionId: '595ffa73-d78a-46c9-b18e-f99548a5be6b', - bidderRequestId: '1cc026909c24c8', - placementCode: 'div-gpt-ad-1438287399331-0', - params: { - publisherId: QUANTCAST_TEST_PUBLISHER, // REQUIRED - Publisher ID provided by Quantcast - battr: [1, 2] // OPTIONAL - Array of blocked creative attributes as per OpenRTB Spec List 5.3 - }, - mediaTypes: { - banner: { - sizes: [[300, 250]] - } - } - }; - - bidderRequest = { - refererInfo: { - page: 'http://example.com/hello.html', - ref: 'http://example.com/hello.html', - domain: 'example.com' - } - }; - - storage.setCookie('__qca', '', 'Thu, 01 Jan 1970 00:00:00 GMT'); - }); - - function setupVideoBidRequest(videoParams, mediaTypesParams) { - bidRequest.params = { - publisherId: 'test-publisher', // REQUIRED - Publisher ID provided by Quantcast - // Video object as specified in OpenRTB 2.5 - video: videoParams - }; - if (mediaTypesParams) { - bidRequest['mediaTypes'] = { - video: mediaTypesParams - } - } - }; - - describe('inherited functions', function () { - it('exists and is a function', function () { - expect(quantcastAdapter.callBids).to.exist.and.to.be.a('function'); - }); - }); - - describe('`isBidRequestValid`', function () { - it('should return `true` when bid has publisherId', function () { - const bidRequest = { - bidder: 'quantcast', - params: { - publisherId: 'my_publisher_id' - } - }; - - expect(qcSpec.isBidRequestValid(bidRequest)).to.equal(true); - }); - - it('should return `false` when bid has no publisherId', function () { - const bidRequest = { - bidder: 'quantcast', - params: { - } - }; - - expect(qcSpec.isBidRequestValid(bidRequest)).to.equal(false); - }); - }); - - describe('`buildRequests`', function () { - it('sends secure bid requests', function () { - const requests = qcSpec.buildRequests([bidRequest]); - const url = parseUrl(requests[0]['url']); - expect(url.protocol).to.equal('https'); - }); - - it('sends bid requests to Quantcast Canary Endpoint if `publisherId` is `test-publisher`', function () { - const requests = qcSpec.buildRequests([bidRequest]); - const url = parseUrl(requests[0]['url']); - expect(url.hostname).to.equal(QUANTCAST_TEST_DOMAIN); - }); - - it('sends bid requests to default endpoint for non standard publisher IDs', function () { - const modifiedBidRequest = Object.assign({}, bidRequest, { - params: Object.assign({}, bidRequest.params, { - publisherId: 'foo-bar', - }), - }); - const requests = qcSpec.buildRequests([modifiedBidRequest]); - expect(requests[0]['url']).to.equal( - `${QUANTCAST_PROTOCOL}://${QUANTCAST_DOMAIN}:${QUANTCAST_PORT}/qchb` - ); - }); - - it('sends bid requests to Quantcast Header Bidding Endpoints via POST', function () { - const requests = qcSpec.buildRequests([bidRequest]); - - expect(requests[0].method).to.equal('POST'); - }); - - const expectedBannerBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [ - { - banner: { - battr: [1, 2], - sizes: [{ width: 300, height: 250 }] - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - } - ], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - it('sends banner bid requests contains all the required parameters', function () { - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests[0].data).to.equal(JSON.stringify(expectedBannerBidRequest)); - }); - - it('supports deprecated banner format', function () { - bidRequest.sizes = bidRequest.mediaTypes.banner.sizes; - delete bidRequest.mediaTypes; - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests[0].data).to.equal(JSON.stringify(expectedBannerBidRequest)); - }); - - it('sends video bid requests containing all the required parameters', function () { - setupVideoBidRequest({ - mimes: ['video/mp4'], // required - minduration: 3, // optional - maxduration: 5, // optional - protocols: [3], // optional - startdelay: 1, // optional - linearity: 1, // optinal - battr: [1, 2], // optional - maxbitrate: 10, // optional - playbackmethod: [1], // optional - delivery: [1], // optional - api: [2, 3] // optional - }, { - context: 'instream', - playerSize: [600, 300] - }); - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const expectedVideoBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [ - { - video: { - mimes: ['video/mp4'], - minduration: 3, - maxduration: 5, - protocols: [3], - startdelay: 1, - linearity: 1, - battr: [1, 2], - maxbitrate: 10, - playbackmethod: [1], - delivery: [1], - api: [2, 3], - w: 600, - h: 300 - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - } - ], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - expect(requests[0].data).to.equal(JSON.stringify(expectedVideoBidRequest)); - }); - - it('sends video bid requests containing all the required parameters from mediaTypes', function() { - setupVideoBidRequest(null, { - mimes: ['video/mp4'], // required - minduration: 3, // optional - maxduration: 5, // optional - protocols: [3], // optional - startdelay: 1, // optional - linearity: 1, // optinal - battr: [1, 2], // optional - maxbitrate: 10, // optional - playbackmethod: [1], // optional - delivery: [1], // optional - api: [2, 3], // optional - context: 'instream', - playerSize: [600, 300] - }); - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const expectedVideoBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [ - { - video: { - mimes: ['video/mp4'], - minduration: 3, - maxduration: 5, - protocols: [3], - startdelay: 1, - linearity: 1, - battr: [1, 2], - maxbitrate: 10, - playbackmethod: [1], - delivery: [1], - api: [2, 3], - w: 600, - h: 300 - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - } - ], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - expect(requests[0].data).to.equal(JSON.stringify(expectedVideoBidRequest)); - }); - - it('overrides video parameters with parameters from adunit', function() { - setupVideoBidRequest({ - mimes: ['video/mp4'] - }, { - context: 'instream', - playerSize: [600, 300] - }); - bidRequest.mediaTypes.video.mimes = ['video/webm']; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const expectedVideoBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [ - { - video: { - mimes: ['video/webm'], - w: 600, - h: 300 - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - } - ], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - expect(requests[0].data).to.equal(JSON.stringify(expectedVideoBidRequest)); - }); - - it('sends video bid request when no video parameters are given', function () { - setupVideoBidRequest(null, { - context: 'instream', - playerSize: [600, 300] - }); - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const expectedVideoBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [ - { - video: { - w: 600, - h: 300 - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - } - ], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - expect(requests[0].data).to.equal(JSON.stringify(expectedVideoBidRequest)); - }); - - it('ignores unsupported video bid requests', function () { - bidRequest.mediaTypes = { - video: { - context: 'outstream', - playerSize: [[550, 310]] - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests).to.be.empty; - }); - - it('parses multi-format bid request', function () { - bidRequest.mediaTypes = { - banner: {sizes: [[300, 250], [728, 90], [250, 250], [468, 60], [320, 50]]}, - native: { - image: {required: true, sizes: [150, 50]}, - title: {required: true, len: 80}, - sponsoredBy: {required: true}, - clickUrl: {required: true}, - privacyLink: {required: false}, - body: {required: true}, - icon: {required: true, sizes: [50, 50]} - }, - video: { - context: 'outstream', - playerSize: [[550, 310]] - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const expectedBidRequest = { - publisherId: QUANTCAST_TEST_PUBLISHER, - requestId: '2f7b179d443f14', - imp: [{ - banner: { - battr: [1, 2], - sizes: [ - {width: 300, height: 250}, - {width: 728, height: 90}, - {width: 250, height: 250}, - {width: 468, height: 60}, - {width: 320, height: 50} - ] - }, - placementCode: 'div-gpt-ad-1438287399331-0', - bidFloor: 1e-10 - }], - site: { - page: 'http://example.com/hello.html', - referrer: 'http://example.com/hello.html', - domain: 'example.com' - }, - bidId: '2f7b179d443f14', - gdprSignal: 0, - uspSignal: 0, - coppa: 0, - prebidJsVersion: '$prebid.version$', - fpa: '' - }; - - expect(requests[0].data).to.equal(JSON.stringify(expectedBidRequest)); - }); - }); - - it('propagates GDPR consent string and signal', function () { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString' - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const parsed = JSON.parse(requests[0].data); - - expect(parsed.gdprSignal).to.equal(1); - expect(parsed.gdprConsent).to.equal('consentString'); - }); - - it('allows TCF v2 request when Quantcast has consent for purpose 1', function() { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - vendor: { - consents: { - '11': true - } - }, - purpose: { - consents: { - '1': true - } - } - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const parsed = JSON.parse(requests[0].data); - - expect(parsed.gdprSignal).to.equal(1); - expect(parsed.gdprConsent).to.equal('consentString'); - }); - - it('blocks TCF v2 request when no consent for Quantcast', function() { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - vendor: { - consents: { - '11': false - } - }, - purpose: { - consents: { - '1': true - } - } - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests).to.equal(undefined); - }); - - it('blocks TCF v2 request when no consent for purpose 1', function() { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - vendor: { - consents: { - '11': true - } - }, - purpose: { - consents: { - '1': false - } - } - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests).to.equal(undefined); - }); - - it('blocks TCF v2 request when Quantcast not allowed by publisher', function () { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - vendor: { - consents: { - '11': true - } - }, - purpose: { - consents: { - '1': true - } - }, - publisher: { - restrictions: { - '1': { - '11': 0 - } - } - } - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests).to.equal(undefined); - }); - - it('blocks TCF v2 request when legitimate interest required', function () { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - vendor: { - consents: { - '11': true - } - }, - purpose: { - consents: { - '1': true - } - }, - publisher: { - restrictions: { - '1': { - '11': 2 - } - } - } - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - - expect(requests).to.equal(undefined); - }); - - it('propagates US Privacy/CCPA consent information', function () { - const bidderRequest = { uspConsent: 'consentString' } - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const parsed = JSON.parse(requests[0].data); - expect(parsed.uspSignal).to.equal(1); - expect(parsed.uspConsent).to.equal('consentString'); - }); - - it('propagates Quantcast first-party cookie (fpa)', function() { - storage.setCookie('__qca', 'P0-TestFPA'); - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const parsed = JSON.parse(requests[0].data); - expect(parsed.fpa).to.equal('P0-TestFPA'); - }); - - describe('propagates coppa', function() { - let sandbox; - beforeEach(() => { - sandbox = sinon.createSandbox(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it('propagates coppa as 1 if coppa param is set to true in the bid request', function () { - bidRequest.params = { - publisherId: 'test_publisher_id', - coppa: true - }; - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'coppa': true - }; - return config[key]; - }); - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - expect(JSON.parse(requests[0].data).coppa).to.equal(1); - }); - - it('propagates coppa as 0 if there is no coppa param or coppa is set to false in the bid request', function () { - const requestsWithoutCoppa = qcSpec.buildRequests([bidRequest], bidderRequest); - expect(JSON.parse(requestsWithoutCoppa[0].data).coppa).to.equal(0); - - bidRequest.params = { - publisherId: 'test_publisher_id', - coppa: false - }; - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'coppa': false - }; - return config[key]; - }); - const requestsWithFalseCoppa = qcSpec.buildRequests([bidRequest], bidderRequest); - expect(JSON.parse(requestsWithFalseCoppa[0].data).coppa).to.equal(0); - }); - }); - - describe('`interpretResponse`', function () { - // The sample response is from https://wiki.corp.qc/display/adinf/QCX - const body = { - bidderCode: 'qcx', // Renaming it to use CamelCase since that is what is used in the Prebid.js variable name - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', // Added this field. This is not used now but could be useful in troubleshooting later on. Specially for sites using iFrames - bids: [ - { - statusCode: 1, - placementCode: 'imp1', // Changing this to placementCode to be reflective - cpm: 4.5, - currency: 'USD', - ad: - '
Quantcast
', - creativeId: 1001, - width: 300, - height: 250, - meta: { - advertiserDomains: ['dailymail.com'] - } - } - ] - }; - - const response = { - body, - headers: {} - }; - - const videoBody = { - bidderCode: 'qcx', - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', - bids: [ - { - statusCode: 1, - placementCode: 'video1', - cpm: 4.5, - currency: 'USD', - videoUrl: 'https://vast.quantserve.com/vast?p=&r=&gdpr=&gdpr_consent=&rand=1337&d=H4sIAAAAAAAAAONi4mIQcrzFqGLi5OzibOzmpGtm4eyia-LoaqDraGRupOtobGJhYuni6GRiYLmLiYWrp5f_BBPDDybGScxcPs7-aRYmpmVVoVJgCSXBkozMYl0gKslI1S1Izk9JBQALkFy_YAAAAA&h=uRnsTjyXbOrXJtBQiaMn239i9GI', - width: 600, - height: 300 - } - ] - }; - - const videoResponse = { - body: videoBody, - headers: {} - }; - - it('should return an empty array if `serverResponse` is `undefined`', function () { - const interpretedResponse = qcSpec.interpretResponse(); - - expect(interpretedResponse.length).to.equal(0); - }); - - it('should return an empty array if the parsed response does NOT include `bids`', function () { - const interpretedResponse = qcSpec.interpretResponse({}); - - expect(interpretedResponse.length).to.equal(0); - }); - - it('should return an empty array if the parsed response has an empty `bids`', function () { - const interpretedResponse = qcSpec.interpretResponse({ bids: [] }); - - expect(interpretedResponse.length).to.equal(0); - }); - - it('should get correct bid response', function () { - const expectedResponse = { - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', - cpm: 4.5, - width: 300, - height: 250, - ad: - '
Quantcast
', - ttl: QUANTCAST_TTL, - creativeId: 1001, - netRevenue: QUANTCAST_NET_REVENUE, - currency: 'USD', - meta: { - advertiserDomains: ['dailymail.com'] - } - }; - const interpretedResponse = qcSpec.interpretResponse(response); - - expect(interpretedResponse[0]).to.deep.equal(expectedResponse); - }); - - it('should include dealId in bid response', function () { - response.body.bids[0].dealId = 'test-dealid'; - const expectedResponse = { - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', - cpm: 4.5, - width: 300, - height: 250, - ad: - '
Quantcast
', - ttl: QUANTCAST_TTL, - creativeId: 1001, - netRevenue: QUANTCAST_NET_REVENUE, - currency: 'USD', - dealId: 'test-dealid', - meta: { - advertiserDomains: ['dailymail.com'] - } - }; - const interpretedResponse = qcSpec.interpretResponse(response); - - expect(interpretedResponse[0]).to.deep.equal(expectedResponse); - }); - - it('should get correct bid response for instream video', function() { - const expectedResponse = { - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', - cpm: 4.5, - width: 600, - height: 300, - vastUrl: 'https://vast.quantserve.com/vast?p=&r=&gdpr=&gdpr_consent=&rand=1337&d=H4sIAAAAAAAAAONi4mIQcrzFqGLi5OzibOzmpGtm4eyia-LoaqDraGRupOtobGJhYuni6GRiYLmLiYWrp5f_BBPDDybGScxcPs7-aRYmpmVVoVJgCSXBkozMYl0gKslI1S1Izk9JBQALkFy_YAAAAA&h=uRnsTjyXbOrXJtBQiaMn239i9GI', - mediaType: 'video', - ttl: QUANTCAST_TTL, - creativeId: undefined, - ad: undefined, - netRevenue: QUANTCAST_NET_REVENUE, - currency: 'USD' - }; - const interpretedResponse = qcSpec.interpretResponse(videoResponse); - - expect(interpretedResponse[0]).to.deep.equal(expectedResponse); - }); - - it('handles no bid response', function () { - const body = { - bidderCode: 'qcx', // Renaming it to use CamelCase since that is what is used in the Prebid.js variable name - requestId: 'erlangcluster@qa-rtb002.us-ec.adtech.com-11417780270886458', // Added this field. This is not used now but could be useful in troubleshooting later on. Specially for sites using iFrames - bids: [] - }; - const response = { - body, - headers: {} - }; - const interpretedResponse = qcSpec.interpretResponse(response); - - expect(interpretedResponse.length).to.equal(0); - }); - - it('should return pixel url when available userSync available', function () { - const syncOptions = { - pixelEnabled: true - }; - const serverResponses = [ - { - body: { - userSync: { - url: 'http://quantcast.com/pixelUrl' - } - } - }, - { - body: { - - } - } - ]; - - const actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); - const expectedSync = { - type: 'image', - url: 'http://quantcast.com/pixelUrl' - }; - expect(actualSyncs.length).to.equal(1); - expect(actualSyncs[0]).to.deep.equal(expectedSync); - qcSpec.resetUserSync(); - }); - - it('should not return user syncs if done already', function () { - const syncOptions = { - pixelEnabled: true - }; - const serverResponses = [ - { - body: { - userSync: { - url: 'http://quantcast.com/pixelUrl' - } - } - }, - { - body: { - - } - } - ]; - - let actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); - const expectedSync = { - type: 'image', - url: 'http://quantcast.com/pixelUrl' - }; - expect(actualSyncs.length).to.equal(1); - expect(actualSyncs[0]).to.deep.equal(expectedSync); - - actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); - expect(actualSyncs.length).to.equal(0); - - qcSpec.resetUserSync(); - }); - }); -}); diff --git a/test/spec/modules/quantcastIdSystem_spec.js b/test/spec/modules/quantcastIdSystem_spec.js deleted file mode 100644 index 157c00e7567..00000000000 --- a/test/spec/modules/quantcastIdSystem_spec.js +++ /dev/null @@ -1,405 +0,0 @@ -import { quantcastIdSubmodule, storage, firePixel, hasCCPAConsent, hasGDPRConsent, checkTCFv2 } from 'modules/quantcastIdSystem.js'; -import * as utils from 'src/utils.js'; -import {coppaDataHandler} from 'src/adapterManager'; -import {attachIdSystem} from '../../../modules/userId/index.js'; -import {createEidsArray} from '../../../modules/userId/eids.js'; -import {expect} from 'chai/index.mjs'; - -describe('QuantcastId module', function () { - beforeEach(function() { - sinon.stub(coppaDataHandler, 'getCoppa'); - sinon.stub(utils, 'triggerPixel'); - sinon.stub(window, 'addEventListener'); - }); - - afterEach(function () { - utils.triggerPixel.restore(); - coppaDataHandler.getCoppa.restore(); - window.addEventListener.restore(); - }); - - it('getId() should return a quantcast id when the Quantcast first party cookie exists', function () { - sinon.stub(storage, 'getCookie').returns('P0-TestFPA'); - const id = quantcastIdSubmodule.getId(); - expect(id).to.be.deep.equal({id: {quantcastId: 'P0-TestFPA'}}); - storage.getCookie.restore(); - }); - - it('getId() should return an empty id when the Quantcast first party cookie is missing', function () { - const id = quantcastIdSubmodule.getId(); - expect(id).to.be.deep.equal({id: undefined}); - }); -}); - -describe('QuantcastId fire pixel', function () { - beforeEach(function () { - storage.setCookie('__qca', '', 'Thu, 01 Jan 1970 00:00:00 GMT'); - sinon.stub(storage, 'setCookie'); - sinon.stub(utils, 'triggerPixel'); - }); - - afterEach(function () { - utils.triggerPixel.restore(); - storage.setCookie.restore(); - }); - - it('fpa should be set when not present on this call', function () { - firePixel('clientId'); - var urlString = utils.triggerPixel.getCall(0).args[0]; - var parsedUrl = utils.parseUrl(urlString); - var urlSearchParams = parsedUrl.search; - assert.equal(urlSearchParams.fpan, '1'); - assert.notEqual(urlSearchParams.fpa, null); - }); - - it('fpa should be extracted from the Quantcast first party cookie when present on this call', function () { - sinon.stub(storage, 'getCookie').returns('P0-TestFPA'); - firePixel('clientId'); - var urlString = utils.triggerPixel.getCall(0).args[0]; - var parsedUrl = utils.parseUrl(urlString); - var urlSearchParams = parsedUrl.search; - assert.equal(urlSearchParams.fpan, '0'); - assert.equal(urlSearchParams.fpa, 'P0-TestFPA'); - storage.getCookie.restore(); - }); - - it('function to trigger pixel is called once', function () { - firePixel('clientId'); - expect(utils.triggerPixel.calledOnce).to.equal(true); - }); - - it('function to trigger pixel is not called when client id is absent', function () { - firePixel(); - expect(utils.triggerPixel.calledOnce).to.equal(false); - }); -}); - -describe('Quantcast CCPA consent check', function() { - it('returns true when CCPA constent string is not present', function() { - expect(hasCCPAConsent()).to.equal(true); - }); - - it("returns true when notice_given or do-not-sell in CCPA constent string is not 'Y' ", function() { - expect(hasCCPAConsent('1NNN')).to.equal(true); - expect(hasCCPAConsent('1YNN')).to.equal(true); - expect(hasCCPAConsent('1NYN')).to.equal(true); - }); - - it("returns false when CCPA consent string is present, and notice_given or do-not-sell in the string is 'Y' ", function() { - expect(hasCCPAConsent('1YYN')).to.equal(false); - }); -}); - -describe('Quantcast GDPR consent check', function() { - it("returns true when GDPR doesn't apply", function() { - expect(hasGDPRConsent({gdprApplies: false})).to.equal(true); - }); - - it('returns false if denied consent, even if special purpose 1 treatment is true in DE', function() { - expect(checkTCFv2({ - gdprApplies: true, - publisherCC: 'DE', - purposeOneTreatment: true, - vendor: { - consents: { '11': false } - }, - purpose: { - consents: { '1': false } - }, - publisher: { - restrictions: { - '1': { - '11': 0 // flatly disallow Quantcast - } - } - } - }, ['1'])).to.equal(false); - }); - - it('returns false if publisher flatly denies required purpose', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true } - }, - purpose: { - consents: { '1': true } - }, - publisher: { - restrictions: { - '1': { - '11': 0 // flatly disallow Quantcast - } - } - } - }, ['1'])).to.equal(false); - }); - - it('returns true if positive consent for required purpose', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true } - }, - purpose: { - consents: { '1': true } - } - }, ['1'])).to.equal(true); - }); - - it('returns false if positive consent but publisher requires legitimate interest for required purpose', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true } - }, - purpose: { - consents: { '1': true } - }, - publisher: { - restrictions: { - '1': { - '11': 2 // require legitimate interest for Quantcast - } - } - } - }, ['1'])).to.equal(false); - }); - - it('returns false if no vendor consent and no legitimate interest', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': false } - }, - purpose: { - consents: { '1': true } - } - }, ['1'])).to.equal(false); - }); - - it('returns false if no purpose consent and no legitimate interest', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true } - }, - purpose: { - consents: { '1': false } - } - }, ['1'])).to.equal(false); - }); - - it('returns false if no consent, but legitimate interest for consent-first purpose, and no restrictions specified', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '1': false }, - legitimateInterests: { '1': true } - } - }, ['1'])).to.equal(false); - }); - - it('returns false if consent, but no legitimate interest for legitimate-interest-first purpose, and no restrictions specified', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '10': true }, - legitimateInterests: { '10': false } - } - }, ['10'])).to.equal(false); - }); - - it('returns true if consent, but no legitimate interest for legitimate-interest-first purpose, and corresponding consent restriction specified', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '10': true }, - legitimateInterests: { '10': false } - }, - publisher: { - restrictions: { - '10': { - '11': 1 // require consent for Quantcast - } - } - } - }, ['10'])).to.equal(true); - }); - - it('returns false if no consent but legitimate interest for required purpose other than 1, but publisher requires consent', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': false }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '10': false }, - legitimateInterests: { '10': true } - }, - publisher: { - restrictions: { - '10': { - '11': 1 // require consent for Quantcast - } - } - } - }, ['10'])).to.equal(false); - }); - - it('returns false if no consent and no legitimate interest for vendor for required purpose other than 1', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': false }, - legitimateInterests: { '11': false } - }, - purpose: { - consents: { '10': false }, - legitimateInterests: { '10': true } - } - }, ['10'])).to.equal(false); - }); - - it('returns false if no consent and no legitimate interest for required purpose other than 1', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': false }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '10': false }, - legitimateInterests: { '10': false } - } - }, ['10'])).to.equal(false); - }); - - it('returns false if no consent but legitimate interest for required purpose, but required purpose is purpose 1', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': false }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { '1': false }, - legitimateInterests: { '1': true } - } - }, ['1'])).to.equal(false); - }); - - it('returns true if different legal bases for multiple required purposes', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { - '1': true, - '10': false - }, - legitimateInterests: { - '1': false, - '10': true - } - }, - publisher: { - restrictions: { - '10': { - '11': 2 // require legitimate interest for Quantcast - } - } - } - })).to.equal(true); - }); - - it('returns true if full consent and legitimate interest for all required purposes with no restrictions specified', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { - '1': true, - '3': true, - '7': true, - '8': true, - '9': true, - '10': true - }, - legitimateInterests: { - '1': true, - '3': true, - '7': true, - '8': true, - '9': true, - '10': true - } - } - })).to.equal(true); - }); - - it('returns false if one of multiple required purposes has no legal basis', function() { - expect(checkTCFv2({ - gdprApplies: true, - vendor: { - consents: { '11': true }, - legitimateInterests: { '11': true } - }, - purpose: { - consents: { - '1': true, - '10': false - }, - legitimateInterests: { - '11': false, - '10': true - } - }, - publisher: { - restrictions: { - '10': { - '11': 1 // require consent for Quantcast - } - } - } - })).to.equal(false); - }); - describe('eids', () => { - before(() => { - attachIdSystem(quantcastIdSubmodule); - }); - it('quantcastId', function() { - const userId = { - quantcastId: 'some-random-id-value' - }; - const newEids = createEidsArray(userId); - expect(newEids.length).to.equal(1); - expect(newEids[0]).to.deep.equal({ - source: 'quantcast.com', - uids: [{ - id: 'some-random-id-value', - atype: 1 - }] - }); - }); - }) -}); diff --git a/test/spec/modules/rhythmoneBidAdapter_spec.js b/test/spec/modules/rhythmoneBidAdapter_spec.js index b9fa0cd37af..40506db90a1 100644 --- a/test/spec/modules/rhythmoneBidAdapter_spec.js +++ b/test/spec/modules/rhythmoneBidAdapter_spec.js @@ -1,6 +1,5 @@ import {spec} from '../../../modules/rhythmoneBidAdapter.js'; import * as utils from '../../../src/utils.js'; -import * as dnt from 'libraries/dnt/index.js'; import * as sinon from 'sinon'; var r1adapter = spec; @@ -414,37 +413,6 @@ describe('rhythmone adapter tests', function () { expect(openrtbRequest.imp[0].banner.format.length).to.equal(1); }); - it('dnt is correctly set to 1', function () { - var bidRequestList = [ - { - 'bidder': 'rhythmone', - 'params': { - 'placementId': 'myplacement', - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[300, 600]] - } - }, - 'adUnitCode': 'div-gpt-ad-1438287399331-0', - 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', - 'bidderRequestId': '418b37f85e772c', - 'auctionId': '18fd8b8b0bd757', - 'bidRequestsCount': 1, - 'bidId': '51ef8751f9aead' - } - ]; - - var dntStub = sinon.stub(dnt, 'getDNT').returns(1); - - var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); - - dntStub.restore(); - - const openrtbRequest = JSON.parse(bidRequest.data); - expect(openrtbRequest.device.dnt).to.equal(1); - }); - it('sets floor to zero', function () { var bidRequestList = [ { diff --git a/test/spec/modules/ringieraxelspringerBidAdapter_spec.js b/test/spec/modules/ringieraxelspringerBidAdapter_spec.js deleted file mode 100644 index 0318a6987c6..00000000000 --- a/test/spec/modules/ringieraxelspringerBidAdapter_spec.js +++ /dev/null @@ -1,10 +0,0 @@ -import { expect } from 'chai'; -import { spec } from 'modules/ringieraxelspringerBidAdapter.js'; - -describe('ringieraxelspringer backward-compatibility shim', function () { - it('should re-export spec from dasBidAdapter', function () { - expect(spec).to.exist; - expect(spec.code).to.equal('das'); - expect(spec.aliases).to.include('ringieraxelspringer'); - }); -}); diff --git a/test/spec/modules/sharethroughBidAdapter_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js index 56f238ff1ba..26e9e57da7c 100644 --- a/test/spec/modules/sharethroughBidAdapter_spec.js +++ b/test/spec/modules/sharethroughBidAdapter_spec.js @@ -963,22 +963,6 @@ describe('sharethrough adapter spec', function () { }); }); - describe('fledge', () => { - it('should attach "ae" as a property to the request if 1) fledge auctions are enabled, and 2) request is display (only supporting display for now)', () => { - // ASSEMBLE - const EXPECTED_AE_VALUE = 1; - - // ACT - bidderRequest.paapi = { enabled: true }; - const builtRequests = spec.buildRequests(bidRequests, bidderRequest); - const ACTUAL_AE_VALUE = builtRequests[0].data.imp[0].ext.ae; - - // ASSERT - expect(ACTUAL_AE_VALUE).to.equal(EXPECTED_AE_VALUE); - expect(builtRequests[1].data.imp[0].ext.ae).to.be.undefined; - }); - }); - describe('isEqtvTest', () => { it('should set publisher id if equativNetworkId param is present', () => { const builtRequest = spec.buildRequests(multiImpBidRequests, bidderRequest)[0]; @@ -1221,53 +1205,6 @@ describe('sharethrough adapter spec', function () { const resp = spec.interpretResponse(response, request)[0]; expect(resp.ttl).to.equal(360); }); - - it('should return correct properties when fledgeAuctionEnabled is true and isEqtvTest is false', () => { - request = spec.buildRequests(bidRequests, bidderRequest)[0]; - response = { - body: { - ext: { - auctionConfigs: { - key: 'value', - }, - }, - seatbid: [ - { - bid: [ - { - id: 'abcd1234', - impid: 'aaaabbbbccccdd', - w: 300, - h: 250, - price: 42, - crid: 'creative', - dealid: 'deal', - adomain: ['domain.com'], - adm: 'markup', - exp: -1, - }, - { - id: 'efgh5678', - impid: 'ddeeeeffffgggg', - w: 300, - h: 250, - price: 42, - crid: 'creative', - dealid: 'deal', - adomain: ['domain.com'], - adm: 'markup', - exp: -1, - }, - ], - }, - ], - }, - }; - - const resp = spec.interpretResponse(response, request); - expect(resp.bids.length).to.equal(2); - expect(resp.paapi).to.deep.equal({ key: 'value' }); - }); }); describe('video', () => { diff --git a/test/spec/modules/shinezRtbBidAdapter_spec.js b/test/spec/modules/shinezRtbBidAdapter_spec.js index 2dd33d7ef5b..3f2dfcc83a8 100644 --- a/test/spec/modules/shinezRtbBidAdapter_spec.js +++ b/test/spec/modules/shinezRtbBidAdapter_spec.js @@ -680,6 +680,8 @@ describe('ShinezRtbBidAdapter', function () { }); describe('unique deal id', function () { + let clock; + before(function () { getGlobal().bidderSettings = { shinezRtb: { @@ -690,27 +692,31 @@ describe('ShinezRtbBidAdapter', function () { after(function () { getGlobal().bidderSettings = {}; }); - const key = 'myKey'; + let key; let uniqueDealId; beforeEach(() => { + clock = useFakeTimers({ + now: Date.now() + }); + key = `myKey_${Date.now()}`; uniqueDealId = getUniqueDealId(storage, key, 0); - }) + }); + + afterEach(() => { + clock.restore(); + }); + + it('should get current unique deal id', function () { + // advance time in a deterministic way + clock.tick(200); + const current = getUniqueDealId(storage, key); + expect(current).to.be.equal(uniqueDealId); + }); - it('should get current unique deal id', function (done) { - // waiting some time so `now` will become past - setTimeout(() => { - const current = getUniqueDealId(storage, key); - expect(current).to.be.equal(uniqueDealId); - done(); - }, 200); - }); - - it('should get new unique deal id on expiration', function (done) { - setTimeout(() => { - const current = getUniqueDealId(storage, key, 100); - expect(current).to.not.be.equal(uniqueDealId); - done(); - }, 200) + it('should get new unique deal id on expiration', function () { + clock.tick(200); + const current = getUniqueDealId(storage, key, 100); + expect(current).to.not.be.equal(uniqueDealId); }); }); diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index f1bd464fbdd..8e7a21a92bb 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -79,29 +79,11 @@ describe('smaatoBidAdapterTest', () => { expect(spec.isBidRequestValid({params: {publisherId: 123}})).to.be.false; }); - describe('for ad pod / long form video requests', () => { - const ADPOD = {video: {context: 'adpod'}} - it('is invalid, when adbreakId is missing', () => { - expect(spec.isBidRequestValid({mediaTypes: ADPOD, params: {publisherId: '123'}})).to.be.false; - }); - - it('is invalid, when adbreakId is present but of wrong type', () => { - expect(spec.isBidRequestValid({mediaTypes: ADPOD, params: {publisherId: '123', adbreakId: 456}})).to.be.false; - }); - - it('is valid, when required params are present', () => { - expect(spec.isBidRequestValid({mediaTypes: ADPOD, params: {publisherId: '123', adbreakId: '456'}})).to.be.true; - }); - - it('is invalid, when forbidden adspaceId param is present', () => { - expect(spec.isBidRequestValid({ - mediaTypes: ADPOD, - params: {publisherId: '123', adbreakId: '456', adspaceId: '42'} - })).to.be.false; - }); + it('is invalid, when adbreakId param is present', () => { + expect(spec.isBidRequestValid({params: {publisherId: '123', adspaceId: '456', adbreakId: '42'}})).to.be.false; }); - describe('for non adpod requests', () => { + describe('for supported requests', () => { it('is invalid, when adspaceId is missing', () => { expect(spec.isBidRequestValid({params: {publisherId: '123'}})).to.be.false; }); @@ -672,299 +654,6 @@ describe('smaatoBidAdapterTest', () => { expect(JSON.parse(reqs[1].data).imp[0].banner).to.not.exist; expect(JSON.parse(reqs[1].data).imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); }); - - describe('ad pod / long form video', () => { - describe('required parameters with requireExactDuration false', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 300; - const DURATION_RANGE = [15, 30]; - const longFormVideoBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: ADBREAK_ID, - }, - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: false - } - }, - bidId: BID_ID - }; - - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(ADPOD_DURATION / DURATION_RANGE[0]); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].bidfloor).to.be.undefined; - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - }); - - it('sends instl if instl exists', () => { - const instl = {instl: 1}; - const bidRequestWithInstl = Object.assign({}, longFormVideoBidRequest, {ortb2Imp: instl}); - - const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].instl).to.equal(1); - expect(req.imp[1].instl).to.equal(1); - }); - - it('sends bidfloor when configured', () => { - const longFormVideoBidRequestWithFloor = Object.assign({}, longFormVideoBidRequest); - longFormVideoBidRequestWithFloor.getFloor = function (arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'video' && - JSON.stringify(arg.size) === JSON.stringify([640, 480])) { - return { - currency: 'USD', - floor: 0.789 - } - } - } - const reqs = spec.buildRequests([longFormVideoBidRequestWithFloor], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.789); - expect(req.imp[1].bidfloor).to.be.equal(0.789); - }); - - it('sends brand category exclusion as true when config is set to true', () => { - config.setConfig({adpod: {brandCategoryExclusion: true}}); - - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(true); - }); - - it('sends brand category exclusion as false when config is set to false', () => { - config.setConfig({adpod: {brandCategoryExclusion: false}}); - - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); - }); - - it('sends brand category exclusion as false when config is not set', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); - }); - }); - describe('required parameters with requireExactDuration true', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 5; - const DURATION_RANGE = [5, 15, 25]; - const longFormVideoBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: ADBREAK_ID, - }, - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: true - } - }, - bidId: BID_ID - }; - - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(DURATION_RANGE.length); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.minduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.minduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - expect(req.imp[2].id).to.be.equal(BID_ID); - expect(req.imp[2].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[2].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[2].video.w).to.be.equal(W); - expect(req.imp[2].video.h).to.be.equal(H); - expect(req.imp[2].video.minduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.maxduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.sequence).to.be.equal(3); - }); - }); - - describe('forwarding of optional parameters', () => { - const MIMES = ['video/mp4', 'video/quicktime', 'video/3gpp', 'video/x-m4v']; - const STARTDELAY = 0; - const LINEARITY = 1; - const SKIP = 1; - const PROTOCOLS = [7]; - const SKIPMIN = 5; - const API = [7]; - const validBasicAdpodBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: 'adbreakId', - }, - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - mimes: MIMES, - startdelay: STARTDELAY, - linearity: LINEARITY, - skip: SKIP, - protocols: PROTOCOLS, - skipmin: SKIPMIN, - api: API - } - }, - bidId: 'bidId' - }; - - it('sends general video fields when they are present', () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.mimes).to.eql(MIMES); - expect(req.imp[0].video.startdelay).to.be.equal(STARTDELAY); - expect(req.imp[0].video.linearity).to.be.equal(LINEARITY); - expect(req.imp[0].video.skip).to.be.equal(SKIP); - expect(req.imp[0].video.protocols).to.eql(PROTOCOLS); - expect(req.imp[0].video.skipmin).to.be.equal(SKIPMIN); - expect(req.imp[0].video.api).to.eql(API); - }); - - it('sends series name when parameter is present', () => { - const SERIES_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeriesName = SERIES_NAME; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.series).to.be.equal(SERIES_NAME); - }); - - it('sends episode name when parameter is present', () => { - const EPISODE_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeName = EPISODE_NAME; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.title).to.be.equal(EPISODE_NAME); - }); - - it('sends season number as string when parameter is present', () => { - const SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST = 42 - const SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST = '42' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeasonNumber = SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.season).to.be.equal(SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST); - }); - - it('sends episode number when parameter is present', () => { - const EPISODE_NUMBER = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeNumber = EPISODE_NUMBER; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.episode).to.be.equal(EPISODE_NUMBER); - }); - - it('sends content length when parameter is present', () => { - const LENGTH = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentLengthSec = LENGTH; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.len).to.be.equal(LENGTH); - }); - - it('sends livestream as 1 when content mode parameter is live', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'live'; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(1); - }); - - it('sends livestream as 0 when content mode parameter is on-demand', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'on-demand'; - - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(0); - }); - - it('doesn\'t send any optional parameters when none are present', () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.requireExactDuration).to.not.exist; - expect(req.site.content).to.not.exist; - }); - }); - }); } }); @@ -1539,7 +1228,6 @@ describe('smaatoBidAdapterTest', () => { }); describe('ad pod', () => { - const bidRequestWithAdpodContext = buildBidRequest({imp: [{video: {ext: {context: 'adpod'}}}]}); const PRIMARY_CAT_ID = 1337 const serverResponse = { body: { @@ -1578,44 +1266,6 @@ describe('smaatoBidAdapterTest', () => { }, headers: {get: () => undefined} }; - - it('sets required values for adpod bid from server response', () => { - const bids = spec.interpretResponse(serverResponse, bidRequestWithAdpodContext); - - expect(bids).to.deep.equal([ - { - requestId: '226416e6e6bf41', - cpm: 0.01, - width: 350, - height: 50, - vastXml: '', - ttl: 300, - creativeId: 'CR69381', - dealId: '12345', - netRevenue: true, - currency: 'USD', - mediaType: 'video', - video: { - context: 'adpod', - durationSeconds: 42 - }, - meta: { - advertiserDomains: ['smaato.com'], - agencyId: 'CM6523', - networkName: 'smaato', - mediaType: 'video' - } - } - ]); - }); - - it('sets primary category id in case of enabled brand category exclusion', () => { - config.setConfig({adpod: {brandCategoryExclusion: true}}); - - const bids = spec.interpretResponse(serverResponse, bidRequestWithAdpodContext) - - expect(bids[0].meta.primaryCatId).to.be.equal(PRIMARY_CAT_ID) - }) }); it('uses correct TTL when expire header exists', () => { diff --git a/test/spec/modules/sspBCBidAdapter_spec.js b/test/spec/modules/sspBCBidAdapter_spec.js index 53261a3a734..5181f0ef02a 100644 --- a/test/spec/modules/sspBCBidAdapter_spec.js +++ b/test/spec/modules/sspBCBidAdapter_spec.js @@ -747,13 +747,6 @@ describe('SSPBC adapter', function () { expect(resultIncorrect.length).to.equal(0); }); - - it('should response with fledge auction configs', function () { - const { bids, fledgeAuctionConfigs } = spec.interpretResponse(serverResponsePaapi, requestSingle); - - expect(bids.length).to.equal(1); - expect(fledgeAuctionConfigs.length).to.equal(1); - }); }); describe('getUserSyncs', function () { diff --git a/test/spec/modules/storageControl_spec.js b/test/spec/modules/storageControl_spec.js index a3fb571256b..ff55f5a2c43 100644 --- a/test/spec/modules/storageControl_spec.js +++ b/test/spec/modules/storageControl_spec.js @@ -4,7 +4,8 @@ import { ENFORCE_OFF, ENFORCE_STRICT, getDisclosures, - storageControlRule + storageControlRule, + deactivate } from '../../../modules/storageControl.js'; import { ACTIVITY_PARAM_COMPONENT_NAME, @@ -14,6 +15,10 @@ import { import {MODULE_TYPE_BIDDER} from '../../../src/activities/modules.js'; import {STORAGE_TYPE_COOKIES} from '../../../src/storageManager.js'; +// since the module is on by default, importing it here turn it on for other tests +// that happen to run together with this suite - turn it off +deactivate(); + describe('storageControl', () => { describe('getDisclosures', () => { let metadata; @@ -208,6 +213,12 @@ describe('storageControl', () => { expect(rule()).to.eql({allow: false, reason: 'denied'}); }); + it('should deny by default when enforcement is not set', () => { + enforcement = undefined; + checkResult = {disclosed: false, parent: false, reason: 'denied'}; + expect(rule()).to.eql({allow: false, reason: 'denied'}); + }); + it('should allow when enforcement is allowAliases and disclosure is done by the aliased module', () => { enforcement = ENFORCE_ALIAS; checkResult = {disclosed: false, parent: true, reason: 'allowed'}; diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index 8c23be4bcd0..87c1a200747 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -1234,181 +1234,6 @@ describe('Taboola Adapter', function () { expect(res[0].meta.dchain).to.deep.equal(expectedDchainRes) }); - it('should interpret display response with PA', function () { - const [bid] = serverResponse.body.seatbid[0].bid; - - const expectedRes = { - 'bids': [ - { - requestId: request.bids[0].bidId, - seatBidId: serverResponse.body.seatbid[0].bid[0].id, - cpm: bid.price, - creativeId: bid.crid, - creative_id: bid.crid, - ttl: 60, - netRevenue: true, - currency: serverResponse.body.cur, - mediaType: 'banner', - ad: bid.adm, - width: bid.w, - height: bid.h, - nurl: 'http://win.example.com/', - meta: { - 'advertiserDomains': bid.adomain - }, - } - ], - 'paapi': [ - { - 'impId': request.bids[0].bidId, - 'config': { - 'seller': 'pa.taboola.com', - 'resolveToConfig': false, - 'sellerSignals': {}, - 'sellerTimeout': 100, - 'perBuyerSignals': { - 'https://pa.taboola.com': { - 'country': 'US', - 'route': 'AM', - 'cct': [ - 0.02241223, - -0.8686833, - 0.96153843 - ], - 'vct': '-1967600173', - 'ccv': null, - 'ect': [ - -0.13584597, - 2.5825605 - ], - 'ri': '100fb73d4064bc', - 'vcv': '165229814', - 'ecv': [ - -0.39882636, - -0.05216012 - ], - 'publisher': 'test-headerbidding', - 'platform': 'DESK' - } - }, - 'auctionSignals': {}, - 'decisionLogicUrl': 'https://pa.taboola.com/score/decisionLogic.js', - 'interestGroupBuyers': [ - 'https://pa.taboola.com' - ], - 'perBuyerTimeouts': { - '*': 50 - } - } - } - ] - } - - const res = spec.interpretResponse(serverResponseWithPa, request) - expect(res).to.deep.equal(expectedRes) - }); - - it('should interpret display response with partialPA', function () { - const [bid] = serverResponse.body.seatbid[0].bid; - const expectedRes = { - 'bids': [ - { - requestId: request.bids[0].bidId, - seatBidId: serverResponse.body.seatbid[0].bid[0].id, - cpm: bid.price, - creativeId: bid.crid, - creative_id: bid.crid, - ttl: 60, - netRevenue: true, - currency: serverResponse.body.cur, - mediaType: 'banner', - ad: bid.adm, - width: bid.w, - height: bid.h, - nurl: 'http://win.example.com/', - meta: { - 'advertiserDomains': bid.adomain - }, - } - ], - 'paapi': [ - { - 'impId': request.bids[0].bidId, - 'config': { - 'seller': undefined, - 'resolveToConfig': undefined, - 'sellerSignals': {}, - 'sellerTimeout': undefined, - 'perBuyerSignals': {}, - 'auctionSignals': {}, - 'decisionLogicUrl': undefined, - 'interestGroupBuyers': undefined, - 'perBuyerTimeouts': undefined - } - } - ] - } - - const res = spec.interpretResponse(serverResponseWithPartialPa, request) - expect(res).to.deep.equal(expectedRes) - }); - - it('should interpret display response with wrong PA', function () { - const [bid] = serverResponse.body.seatbid[0].bid; - - const expectedRes = [ - { - requestId: request.bids[0].bidId, - seatBidId: serverResponse.body.seatbid[0].bid[0].id, - cpm: bid.price, - creativeId: bid.crid, - creative_id: bid.crid, - ttl: 60, - netRevenue: true, - currency: serverResponse.body.cur, - mediaType: 'banner', - ad: bid.adm, - width: bid.w, - height: bid.h, - nurl: 'http://win.example.com/', - meta: { - 'advertiserDomains': bid.adomain - }, - } - ] - - const res = spec.interpretResponse(serverResponseWithWrongPa, request) - expect(res).to.deep.equal(expectedRes) - }); - - it('should interpret display response with empty igbid wrong PA', function () { - const [bid] = serverResponse.body.seatbid[0].bid; - - const expectedRes = [ - { - requestId: request.bids[0].bidId, - seatBidId: serverResponse.body.seatbid[0].bid[0].id, - cpm: bid.price, - creativeId: bid.crid, - creative_id: bid.crid, - ttl: 60, - netRevenue: true, - currency: serverResponse.body.cur, - mediaType: 'banner', - ad: bid.adm, - width: bid.w, - height: bid.h, - nurl: 'http://win.example.com/', - meta: { - 'advertiserDomains': bid.adomain - }, - } - ] - - const res = spec.interpretResponse(serverResponseWithEmptyIgbidWIthWrongPa, request) - expect(res).to.deep.equal(expectedRes) - }); - it('should set the correct ttl form the response', function () { // set exp-ttl to be 125 const [bid] = serverResponse.body.seatbid[0].bid; diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js index c698473260f..6aaf4dd64b5 100644 --- a/test/spec/modules/teadsBidAdapter_spec.js +++ b/test/spec/modules/teadsBidAdapter_spec.js @@ -889,7 +889,6 @@ describe('teadsBidAdapter', () => { id5Id: toEid('id5-sync.com', 'id5Id-id'), criteoId: toEid('criteo.com', 'criteoId-id'), yahooConnectId: toEid('yahoo.com', 'yahooConnectId-id'), - quantcastId: toEid('quantcast.com', 'quantcastId-id'), epsilonPublisherLinkId: toEid('epsilon.com', 'epsilonPublisherLinkId-id'), publisherFirstPartyViewerId: toEid('pubcid.org', 'publisherFirstPartyViewerId-id'), merkleId: toEid('merkleinc.com', 'merkleId-id'), @@ -957,7 +956,6 @@ describe('teadsBidAdapter', () => { expect(payload['id5Id']).to.equal('id5Id-id'); expect(payload['criteoId']).to.equal('criteoId-id'); expect(payload['yahooConnectId']).to.equal('yahooConnectId-id'); - expect(payload['quantcastId']).to.equal('quantcastId-id'); expect(payload['epsilonPublisherLinkId']).to.equal('epsilonPublisherLinkId-id'); expect(payload['publisherFirstPartyViewerId']).to.equal('publisherFirstPartyViewerId-id'); expect(payload['merkleId']).to.equal('merkleId-id'); diff --git a/test/spec/modules/topLevelPaapi_spec.js b/test/spec/modules/topLevelPaapi_spec.js deleted file mode 100644 index c08a14f899f..00000000000 --- a/test/spec/modules/topLevelPaapi_spec.js +++ /dev/null @@ -1,515 +0,0 @@ -import { - addPaapiConfigHook, - getPAAPIConfig, - registerSubmodule, - reset as resetPaapi -} from '../../../modules/paapi.js'; -import {config} from 'src/config.js'; -import {BID_STATUS, EVENTS} from 'src/constants.js'; -import * as events from 'src/events.js'; -import { - getPaapiAdId, - getPAAPIBids, - getRenderingDataHook, markWinningBidHook, - parsePaapiAdId, - parsePaapiSize, resizeCreativeHook, - topLevelPAAPI -} from '../../../modules/topLevelPaapi.js'; -import {auctionManager} from '../../../src/auctionManager.js'; -import {expect} from 'chai/index.js'; -import {getBidToRender} from '../../../src/adRendering.js'; - -describe('topLevelPaapi', () => { - let sandbox, auctionConfig, next, auctionId, auctions; - before(() => { - resetPaapi(); - }); - beforeEach(() => { - registerSubmodule(topLevelPAAPI); - }); - afterEach(() => { - resetPaapi(); - }); - beforeEach(() => { - sandbox = sinon.createSandbox(); - auctions = {}; - sandbox.stub(auctionManager.index, 'getAuction').callsFake(({auctionId}) => auctions[auctionId]?.auction); - next = sinon.stub(); - auctionId = 'auct'; - auctionConfig = { - seller: 'mock.seller' - }; - config.setConfig({ - paapi: { - enabled: true, - defaultForSlots: 1 - } - }); - }); - afterEach(() => { - config.resetConfig(); - sandbox.restore(); - }); - - function addPaapiConfig(adUnitCode, auctionConfig, _auctionId = auctionId) { - let auction = auctions[_auctionId]; - if (!auction) { - auction = auctions[_auctionId] = { - auction: {}, - adUnits: {} - }; - } - if (!auction.adUnits.hasOwnProperty(adUnitCode)) { - auction.adUnits[adUnitCode] = { - code: adUnitCode, - ortb2Imp: { - ext: { - paapi: { - requestedSize: { - width: 123, - height: 321 - } - } - } - } - }; - } - addPaapiConfigHook(next, {adUnitCode, auctionId: _auctionId}, { - config: { - ...auctionConfig, - auctionId: _auctionId, - adUnitCode - } - }); - } - - function endAuctions() { - Object.entries(auctions).forEach(([auctionId, {adUnits}]) => { - events.emit(EVENTS.AUCTION_END, {auctionId, adUnitCodes: Object.keys(adUnits), adUnits: Object.values(adUnits)}); - }); - } - - describe('when configured', () => { - let auctionConfig; - beforeEach(() => { - auctionConfig = { - seller: 'top.seller', - decisionLogicURL: 'https://top.seller/decision-logic.js' - }; - config.mergeConfig({ - paapi: { - topLevelSeller: { - auctionConfig, - autorun: false - } - } - }); - }); - - it('should augment config returned by getPAAPIConfig', () => { - addPaapiConfig('au', auctionConfig); - endAuctions(); - sinon.assert.match(getPAAPIConfig().au, auctionConfig); - }); - - it('should not choke if auction config is not defined', () => { - const cfg = config.getConfig('paapi'); - delete cfg.topLevelSeller.auctionConfig; - config.setConfig(cfg); - addPaapiConfig('au', auctionConfig); - endAuctions(); - expect(getPAAPIConfig().au.componentAuctions).to.exist; - }); - - it('should default resolveToConfig: false', () => { - addPaapiConfig('au', auctionConfig); - endAuctions(); - expect(getPAAPIConfig()['au'].resolveToConfig).to.eql(false); - }); - - describe('when autoRun is set', () => { - let origRaa; - beforeEach(() => { - origRaa = navigator.runAdAuction; - navigator.runAdAuction = sinon.stub(); - }); - afterEach(() => { - navigator.runAdAuction = origRaa; - }); - - it('should start auctions automatically, when autoRun is set', () => { - config.mergeConfig({ - paapi: { - topLevelSeller: { - autorun: true - } - } - }) - addPaapiConfig('au', auctionConfig); - endAuctions(); - sinon.assert.called(navigator.runAdAuction); - }); - }); - - describe('getPAAPIBids', () => { - Object.entries({ - 'a string URN': { - pack: (val) => val, - unpack: (urn) => ({urn}), - canRender: true, - }, - 'a frameConfig object': { - pack: (val) => ({val}), - unpack: (val) => ({frameConfig: {val}}), - canRender: false - } - }).forEach(([t, {pack, unpack, canRender}]) => { - describe(`when runAdAuction returns ${t}`, () => { - let raa; - beforeEach(() => { - raa = sinon.stub().callsFake((cfg) => { - const {auctionId, adUnitCode} = cfg.componentAuctions[0]; - return Promise.resolve(pack(`raa-${adUnitCode}-${auctionId}`)); - }); - }); - - function getBids(filters) { - return getPAAPIBids(filters, raa); - } - - function expectBids(actual, expected) { - expect(Object.keys(actual)).to.eql(Object.keys(expected)); - Object.entries(expected).forEach(([au, val]) => { - sinon.assert.match(actual[au], val == null ? val : { - adId: sinon.match(val => parsePaapiAdId(val)[1] === au), - width: 123, - height: 321, - source: 'paapi', - ...unpack(val) - }); - }); - } - - describe('with one auction config', () => { - beforeEach(() => { - addPaapiConfig('au', auctionConfig, 'auct'); - endAuctions(); - }); - it('should resolve to raa result', () => { - return getBids({adUnitCode: 'au', auctionId}).then(result => { - sinon.assert.calledOnce(raa); - sinon.assert.calledWith( - raa, - sinon.match({ - ...auctionConfig, - componentAuctions: sinon.match([ - sinon.match({ - ...auctionConfig, - auctionId: 'auct', - adUnitCode: 'au' - }) - ]) - }) - ); - expectBids(result, {au: 'raa-au-auct'}); - }); - }); - - Object.entries({ - 'returns null': () => Promise.resolve(), - 'throws': () => { throw new Error() }, - 'rejects': () => Promise.reject(new Error()) - }).forEach(([t, behavior]) => { - it('should resolve to null when runAdAuction returns null', () => { - raa = sinon.stub().callsFake(behavior); - return getBids({adUnitCode: 'au', auctionId: 'auct'}).then(result => { - expectBids(result, {au: null}); - }); - }); - }) - - it('should resolve to the same result when called again', () => { - getBids({adUnitCode: 'au', auctionId}); - return getBids({adUnitCode: 'au', auctionId: 'auct'}).then(result => { - sinon.assert.calledOnce(raa); - expectBids(result, {au: 'raa-au-auct'}); - }); - }); - - describe('events', () => { - beforeEach(() => { - sandbox.stub(events, 'emit'); - }); - it('should fire PAAPI_RUN_AUCTION', () => { - return Promise.all([ - getBids({adUnitCode: 'au', auctionId}), - getBids({adUnitCode: 'other', auctionId}) - ]).then(() => { - sinon.assert.calledWith(events.emit, EVENTS.RUN_PAAPI_AUCTION, { - adUnitCode: 'au', - auctionId, - auctionConfig: sinon.match(auctionConfig) - }); - sinon.assert.neverCalledWith(events.emit, EVENTS.RUN_PAAPI_AUCTION, { - adUnitCode: 'other' - }); - }); - }); - it('should fire PAAPI_BID', () => { - return getBids({adUnitCode: 'au', auctionId}).then(() => { - sinon.assert.calledWith(events.emit, EVENTS.PAAPI_BID, sinon.match({ - ...unpack('raa-au-auct'), - adUnitCode: 'au', - auctionId: 'auct' - })); - }); - }); - it('should fire PAAPI_NO_BID', () => { - raa = sinon.stub().callsFake(() => Promise.resolve(null)); - return getBids({adUnitCode: 'au', auctionId}).then(() => { - sinon.assert.calledWith(events.emit, EVENTS.PAAPI_NO_BID, sinon.match({ - adUnitCode: 'au', - auctionId: 'auct' - })); - }); - }); - - it('should fire PAAPI_ERROR', () => { - raa = sinon.stub().callsFake(() => Promise.reject(new Error('message'))); - return getBids({adUnitCode: 'au', auctionId}).then(res => { - expect(res).to.eql({au: null}); - sinon.assert.calledWith(events.emit, EVENTS.PAAPI_ERROR, sinon.match({ - adUnitCode: 'au', - auctionId: 'auct', - error: sinon.match({message: 'message'}) - })); - }); - }); - }); - - function getBidToRenderPm(adId, forRender = true) { - return new Promise((resolve) => getBidToRender(adId, forRender, resolve)); - } - - it('should hook into getBidToRender', () => { - return getBids({adUnitCode: 'au', auctionId}).then(res => { - return getBidToRenderPm(res.au.adId).then(bidToRender => [res.au, bidToRender]) - }).then(([paapiBid, bidToRender]) => { - if (canRender) { - expect(bidToRender).to.eql(paapiBid) - } else { - expect(bidToRender).to.not.exist; - } - }); - }); - - describe('when overrideWinner is set', () => { - let mockContextual; - beforeEach(() => { - mockContextual = { - adId: 'mock', - adUnitCode: 'au' - } - sandbox.stub(auctionManager, 'findBidByAdId').returns(mockContextual); - config.mergeConfig({ - paapi: { - topLevelSeller: { - overrideWinner: true - } - } - }); - }); - - it(`should ${!canRender ? 'NOT' : ''} override winning bid for the same adUnit`, () => { - return Promise.all([ - getBids({adUnitCode: 'au', auctionId}).then(res => res.au), - getBidToRenderPm(mockContextual.adId) - ]).then(([paapiBid, bidToRender]) => { - if (canRender) { - expect(bidToRender).to.eql(paapiBid); - expect(paapiBid.overriddenAdId).to.eql(mockContextual.adId); - } else { - expect(bidToRender).to.eql(mockContextual) - } - }) - }); - - it('should not override when the ad unit has no paapi winner', () => { - mockContextual.adUnitCode = 'other'; - return getBidToRenderPm(mockContextual.adId).then(bidToRender => { - expect(bidToRender).to.eql(mockContextual); - }) - }); - - it('should not override when already a paapi bid', () => { - return getBids({adUnitCode: 'au', auctionId}).then(res => { - return getBidToRenderPm(res.au.adId).then((bidToRender) => [bidToRender, res.au]); - }).then(([bidToRender, paapiBid]) => { - expect(bidToRender).to.eql(canRender ? paapiBid : mockContextual) - }) - }); - - if (canRender) { - it('should not not override when the bid was already rendered', () => { - getBids(); - return getBidToRenderPm(mockContextual.adId).then((bid) => { - // first pass - paapi wins over contextual - expect(bid.source).to.eql('paapi'); - bid.status = BID_STATUS.RENDERED; - return getBidToRenderPm(mockContextual.adId, false).then(bidToRender => [bid, bidToRender]) - }).then(([paapiBid, bidToRender]) => { - // if `forRender` = false (bit retrieved for x-domain events and such) - // the referenced bid is still paapi - expect(bidToRender).to.eql(paapiBid); - return getBidToRenderPm(mockContextual.adId); - }).then(bidToRender => { - // second pass, paapi has been rendered, contextual should win - expect(bidToRender).to.eql(mockContextual); - bidToRender.status = BID_STATUS.RENDERED; - return getBidToRenderPm(mockContextual.adId, false); - }).then(bidToRender => { - // if the contextual bid has been rendered, it's the one being referenced - expect(bidToRender).to.eql(mockContextual); - }); - }) - } - }); - }); - - it('should resolve the same result from different filters', () => { - const targets = { - auct1: ['au1', 'au2'], - auct2: ['au1', 'au3'] - }; - Object.entries(targets).forEach(([auctionId, adUnitCodes]) => { - adUnitCodes.forEach(au => addPaapiConfig(au, auctionConfig, auctionId)); - }); - endAuctions(); - return Promise.all( - [ - [ - {adUnitCode: 'au1', auctionId: 'auct1'}, - { - au1: 'raa-au1-auct1' - } - ], - [ - {}, - { - au1: 'raa-au1-auct2', - au2: 'raa-au2-auct1', - au3: 'raa-au3-auct2' - } - ], - [ - {auctionId: 'auct1'}, - { - au1: 'raa-au1-auct1', - au2: 'raa-au2-auct1' - } - ], - [ - {adUnitCode: 'au1'}, - { - au1: 'raa-au1-auct2' - } - ], - ].map(([filters, expected]) => getBids(filters).then(res => [res, expected])) - ).then(res => { - res.forEach(([actual, expected]) => { - expectBids(actual, expected); - }); - }); - }); - }); - }); - }); - }); - - describe('when not configured', () => { - it('should not alter configs returned by getPAAPIConfig', () => { - addPaapiConfig('au', auctionConfig); - endAuctions(); - expect(getPAAPIConfig().au.seller).to.not.exist; - }); - }); - - describe('paapi adId', () => { - [ - ['auctionId', 'adUnitCode'], - ['auction:id', 'adUnit:code'], - ['auction:uid', 'ad:unit'] - ].forEach(([auctionId, adUnitCode]) => { - it(`can encode and decode ${auctionId}, ${adUnitCode}`, () => { - expect(parsePaapiAdId(getPaapiAdId(auctionId, adUnitCode))).to.eql([auctionId, adUnitCode]); - }); - }); - - [undefined, null, 'not-a-paapi-ad', 'paapi:/malformed'].forEach(adId => { - it(`returns null for adId ${adId}`, () => { - expect(parsePaapiAdId(adId)).to.not.exist; - }); - }); - }); - - describe('parsePaapiSize', () => { - [ - [null, null], - [undefined, null], - [123, 123], - ['123', 123], - ['123px', 123], - ['1sw', null], - ['garbage', null] - ].forEach(([input, expected]) => { - it(`can parse ${input} => ${expected}`, () => { - expect(parsePaapiSize(input)).to.eql(expected); - }); - }); - }); - - describe('rendering hooks', () => { - let next; - beforeEach(() => { - next = sinon.stub() - next.bail = sinon.stub() - }); - describe('getRenderingDataHook', () => { - it('intercepts paapi bids', () => { - getRenderingDataHook(next, { - source: 'paapi', - width: 123, - height: null, - urn: 'url' - }); - sinon.assert.calledWith(next.bail, { - width: 123, - height: null, - adUrl: 'url' - }); - }); - it('does not touch non-paapi bids', () => { - getRenderingDataHook(next, {bid: 'data'}, {other: 'options'}); - sinon.assert.calledWith(next, {bid: 'data'}, {other: 'options'}); - }); - }); - - describe('markWinnigBidsHook', () => { - beforeEach(() => { - sandbox.stub(events, 'emit'); - }); - it('handles paapi bids', () => { - const bid = {source: 'paapi'}; - markWinningBidHook(next, bid); - sinon.assert.notCalled(next); - sinon.assert.called(next.bail); - sinon.assert.calledWith(events.emit, EVENTS.BID_WON, bid); - }); - it('ignores non-paapi bids', () => { - markWinningBidHook(next, {other: 'bid'}); - sinon.assert.calledWith(next, {other: 'bid'}); - sinon.assert.notCalled(next.bail); - }); - }); - }); -}); diff --git a/test/spec/modules/trafficgateBidAdapter_spec.js b/test/spec/modules/trafficgateBidAdapter_spec.js index 27550b2cd20..c51e820947f 100644 --- a/test/spec/modules/trafficgateBidAdapter_spec.js +++ b/test/spec/modules/trafficgateBidAdapter_spec.js @@ -12,7 +12,6 @@ import 'modules/multibid/index.js'; import 'modules/priceFloors.js'; import 'modules/consentManagementTcf.js'; import 'modules/consentManagementUsp.js'; -import 'modules/paapi.js'; import {deepClone} from 'src/utils.js'; import {addFPDToBidderRequest} from '../../helpers/fpd.js'; @@ -847,38 +846,6 @@ describe('TrafficgateOpenxRtbAdapter', function () { }); }); - context('do not track (DNT)', function() { - let doNotTrackStub; - - beforeEach(function () { - doNotTrackStub = sinon.stub(dnt, 'getDNT'); - }); - afterEach(function() { - doNotTrackStub.restore(); - }); - - it('when there is a do not track, should send a dnt', async function () { - doNotTrackStub.returns(1); - - const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); - expect(request[0].data.device.dnt).to.equal(1); - }); - - it('when there is not do not track, don\'t send dnt', async function () { - doNotTrackStub.returns(0); - - const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); - expect(request[0].data.device.dnt).to.equal(0); - }); - - it('when there is no defined do not track, don\'t send dnt', async function () { - doNotTrackStub.returns(null); - - const request = spec.buildRequests(bidRequestsWithMediaTypes, await addFPDToBidderRequest(mockBidderRequest)); - expect(request[0].data.device.dnt).to.equal(0); - }); - }); - context('supply chain (schain)', function () { let bidRequests; let schainConfig; diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index 19c537e4da3..72c6baff8cc 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -892,12 +892,6 @@ describe('triplelift adapter', function () { const url = request.url; expect(url).to.match(/(\?|&)us_privacy=1YYY/); }); - it('should pass fledge signal when Triplelift is eligible for fledge', function() { - bidderRequest.paapi = {enabled: true}; - const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); - const url = request.url; - expect(url).to.match(/(\?|&)fledge=true/); - }); it('should return coppa param when COPPA config is set to true', function() { sinon.stub(config, 'getConfig').withArgs('coppa').returns(true); const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); @@ -1400,57 +1394,6 @@ describe('triplelift adapter', function () { expect(result[2].meta.networkId).to.equal('5989'); expect(result[3].meta.networkId).to.equal('5989'); }); - - it('should return fledgeAuctionConfigs if PAAPI response is received', function() { - response.body.paapi = [ - { - imp_id: '0', - auctionConfig: { - seller: 'https://3lift.com', - decisionLogicUrl: 'https://3lift.com/decision_logic.js', - interestGroupBuyers: ['https://some_buyer.com'], - perBuyerSignals: { - 'https://some_buyer.com': { a: 1 } - } - } - }, - { - imp_id: '2', - auctionConfig: { - seller: 'https://3lift.com', - decisionLogicUrl: 'https://3lift.com/decision_logic.js', - interestGroupBuyers: ['https://some_other_buyer.com'], - perBuyerSignals: { - 'https://some_other_buyer.com': { b: 2 } - } - } - } - ]; - - const result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); - - expect(result).to.have.property('bids'); - expect(result).to.have.property('paapi'); - expect(result.paapi.length).to.equal(2); - expect(result.paapi[0].bidId).to.equal('30b31c1838de1e'); - expect(result.paapi[1].bidId).to.equal('73edc0ba8de203'); - expect(result.paapi[0].config).to.deep.equal( - { - 'seller': 'https://3lift.com', - 'decisionLogicUrl': 'https://3lift.com/decision_logic.js', - 'interestGroupBuyers': ['https://some_buyer.com'], - 'perBuyerSignals': { 'https://some_buyer.com': { 'a': 1 } } - } - ); - expect(result.paapi[1].config).to.deep.equal( - { - 'seller': 'https://3lift.com', - 'decisionLogicUrl': 'https://3lift.com/decision_logic.js', - 'interestGroupBuyers': ['https://some_other_buyer.com'], - 'perBuyerSignals': { 'https://some_other_buyer.com': { 'b': 2 } } - } - ); - }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/twistDigitalBidAdapter_spec.js b/test/spec/modules/twistDigitalBidAdapter_spec.js index ea3779c8be8..25a521d957d 100644 --- a/test/spec/modules/twistDigitalBidAdapter_spec.js +++ b/test/spec/modules/twistDigitalBidAdapter_spec.js @@ -639,15 +639,6 @@ describe('TwistDigitalBidAdapter', function () { expect(requests).to.have.length(2); }); - it('should set fledge correctly if enabled', function () { - config.resetConfig(); - const bidderRequest = utils.deepClone(BIDDER_REQUEST); - bidderRequest.paapi = {enabled: true}; - deepSetValue(bidderRequest, 'ortb2Imp.ext.ae', 1); - const requests = adapter.buildRequests([BID], bidderRequest); - expect(requests[0].data.fledge).to.equal(1); - }); - after(function () { getGlobal().bidderSettings = {}; config.resetConfig(); diff --git a/test/spec/modules/valuadBidAdapter_spec.js b/test/spec/modules/valuadBidAdapter_spec.js index d2e05930619..4a27bbd32df 100644 --- a/test/spec/modules/valuadBidAdapter_spec.js +++ b/test/spec/modules/valuadBidAdapter_spec.js @@ -6,7 +6,6 @@ import { BANNER } from 'src/mediaTypes.js'; import { deepClone, generateUUID } from 'src/utils.js'; import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; -import * as dnt from 'libraries/dnt/index.js'; import * as gptUtils from 'libraries/gptUtils/gptUtils.js'; import * as refererDetection from 'src/refererDetection.js'; import * as BoundingClientRect from 'libraries/boundingClientRect/boundingClientRect.js'; @@ -122,7 +121,6 @@ describe('ValuadAdapter', function () { }); sandbox.stub(utils, 'canAccessWindowTop').returns(true); - sandbox.stub(dnt, 'getDNT').returns(false); sandbox.stub(utils, 'generateUUID').returns('test-uuid'); sandbox.stub(refererDetection, 'parseDomain').returns('test.com'); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index ab0820ef32e..77aaeb8a458 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -659,15 +659,6 @@ describe('VidazooBidAdapter', function () { expect(requests).to.have.length(2); }); - it('should set fledge correctly if enabled', function () { - config.resetConfig(); - const bidderRequest = utils.deepClone(BIDDER_REQUEST); - bidderRequest.paapi = {enabled: true}; - deepSetValue(bidderRequest, 'ortb2Imp.ext.ae', 1); - const requests = adapter.buildRequests([BID], bidderRequest); - expect(requests[0].data.fledge).to.equal(1); - }); - after(function () { getGlobal().bidderSettings = {}; config.resetConfig(); diff --git a/test/spec/unit/adRendering_spec.js b/test/spec/unit/adRendering_spec.js index b7be604b85b..bc5acd10317 100644 --- a/test/spec/unit/adRendering_spec.js +++ b/test/spec/unit/adRendering_spec.js @@ -35,27 +35,6 @@ describe('adRendering', () => { sandbox.restore(); }) - describe('getBidToRender', () => { - beforeEach(() => { - sandbox.stub(auctionManager, 'findBidByAdId').callsFake(() => 'auction-bid') - }); - it('should default to bid from auctionManager', async () => { - await new Promise((resolve) => { - getBidToRender('adId', true, (res) => { - expect(res).to.eql('auction-bid'); - sinon.assert.calledWith(auctionManager.findBidByAdId, 'adId'); - resolve(); - }) - }) - }); - it('should, by default, not give up the thread', () => { - let ran = false; - getBidToRender('adId', true, () => { - ran = true; - }); - expect(ran).to.be.true; - }) - }) describe('getRenderingData', () => { let bidResponse; beforeEach(() => { diff --git a/test/spec/unit/core/ajax_spec.js b/test/spec/unit/core/ajax_spec.js index dd62bed97c1..2646ed2cc10 100644 --- a/test/spec/unit/core/ajax_spec.js +++ b/test/spec/unit/core/ajax_spec.js @@ -186,7 +186,7 @@ describe('toFetchRequest', () => { }); describe('chrome options', () => { - ['browsingTopics', 'adAuctionHeaders'].forEach(option => { + ['browsingTopics'].forEach(option => { Object.entries({ [`${option} = true`]: [{[option]: true}, true], [`${option} = false`]: [{[option]: false}, false], diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index 79b09cfbe11..ff390b95268 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -1,4 +1,4 @@ -import {addPaapiConfig, addIGBuyer, isValid, newBidder, registerBidder} from 'src/adapters/bidderFactory.js'; +import {isValid, newBidder, registerBidder} from 'src/adapters/bidderFactory.js'; import adapterManager from 'src/adapterManager.js'; import * as ajax from 'src/ajax.js'; import {expect} from 'chai'; @@ -1640,59 +1640,6 @@ describe('bidderFactory', () => { bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); sinon.assert.calledWith(addBidResponseStub, 'mock/placement', sinon.match(bid)); }) - - describe('when response has PAAPI config', function() { - let paapiStub; - - function paapiHook(next, ...args) { - paapiStub(...args); - } - - function runBidder(response) { - const bidder = newBidder(spec); - spec.interpretResponse.returns(response); - bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - } - - before(() => { - addPaapiConfig.before(paapiHook); - }); - - after(() => { - addPaapiConfig.getHooks({hook: paapiHook}).remove(); - }) - - beforeEach(function () { - paapiStub = sinon.stub(); - }); - - describe(`when response has paapi`, () => { - it('should call paapi config hook with auction configs', function () { - runBidder({ - bids: bids, - paapi: [paapiConfig] - }); - expect(paapiStub.calledOnce).to.equal(true); - sinon.assert.calledWith(paapiStub, bidRequest.bids[0], paapiConfig); - sinon.assert.calledWith(addBidResponseStub, 'mock/placement', sinon.match(bids[0])); - }); - - Object.entries({ - 'missing': undefined, - 'an empty array': [] - }).forEach(([t, bids]) => { - it(`should call paapi config hook with PAAPI configs even when bids is ${t}`, function () { - runBidder({ - bids, - paapi: [paapiConfig] - }); - expect(paapiStub.calledOnce).to.be.true; - sinon.assert.calledWith(paapiStub, bidRequest.bids[0], paapiConfig); - expect(addBidResponseStub.calledOnce).to.equal(false); - }); - }); - }); - }); }); }); diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index 3ce5db91ef2..344229346c5 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -1113,17 +1113,6 @@ describe('targeting tests', function () { expect(targeting[nativeAdUnitCode].hb_pb_dgads).to.exist.and.to.equal(nativeBid2.pbMg); }); } - - it('does not include adpod type bids in the getBidsReceived results', function () { - const adpodBid = utils.deepClone(bid1); - adpodBid.video = { context: 'adpod', durationSeconds: 15, durationBucket: 15 }; - adpodBid.cpm = 5; - bidsReceived.push(adpodBid); - - const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); - expect(targeting['/123456/header-bid-tag-0']).to.contain.keys('hb_deal', 'hb_adid', 'hb_bidder'); - expect(targeting['/123456/header-bid-tag-0']['hb_adid']).to.equal(bid1.adId); - }); }); // end getAllTargeting tests describe('getAllTargeting will work correctly when a hook raises has modified flag in getHighestCpmBidsFromBidPool', function () { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 5939298765e..105b3392d00 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -26,7 +26,6 @@ import {mockFpdEnrichments} from '../../helpers/fpd.js'; import {deepAccess, deepSetValue, generateUUID} from '../../../src/utils.js'; import {getCreativeRenderer} from '../../../src/creativeRenderers.js'; import {BID_STATUS, EVENTS, GRANULARITY_OPTIONS, PB_LOCATOR, TARGETING_KEYS} from 'src/constants.js'; -import {getBidToRender} from '../../../src/adRendering.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; var assert = require('chai').assert; @@ -3243,14 +3242,6 @@ describe('Unit: Prebid Module', function () { assert.ok(spyEventsOn.calledWith('bidWon', Function)); events.on.restore(); }); - - it('should emit event BID_ACCEPTED when invoked', function () { - var callback = sinon.spy(); - pbjs.onEvent('bidAccepted', callback); - events.emit(EVENTS.BID_ACCEPTED); - sinon.assert.calledOnce(callback); - }); - describe('beforeRequestBids', function () { let bidRequestedHandler; let beforeRequestBidsHandler; diff --git a/test/spec/unit/secureCreatives_spec.js b/test/spec/unit/secureCreatives_spec.js index 084341358b4..9e3f2cab132 100644 --- a/test/spec/unit/secureCreatives_spec.js +++ b/test/spec/unit/secureCreatives_spec.js @@ -14,24 +14,12 @@ import 'modules/nativeRendering.js'; import {expect} from 'chai'; import {AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS} from 'src/constants.js'; -import {getBidToRender} from '../../../src/adRendering.js'; import {PUC_MIN_VERSION} from 'src/creativeRenderers.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; describe('secureCreatives', () => { let sandbox; - function getBidToRenderHook(next, ...args) { - // make sure that bids can be retrieved asynchronously - setTimeout(() => next(...args)) - } - before(() => { - getBidToRender.before(getBidToRenderHook); - }); - after(() => { - getBidToRender.getHooks({hook: getBidToRenderHook}).remove() - }); - beforeEach(() => { sandbox = sinon.createSandbox(); }); diff --git a/test/test_deps.js b/test/test_deps.js index 5f0ab890035..a960d5f2d87 100644 --- a/test/test_deps.js +++ b/test/test_deps.js @@ -56,6 +56,5 @@ require('test/mocks/adloaderStub.js'); require('test/mocks/xhr.js'); require('test/mocks/analyticsStub.js'); require('test/mocks/ortbConverter.js') -require('modules/categoryTranslation.js'); require('modules/rtdModule/index.js'); require('modules/fpdModule/index.js');