diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index e4a736c0b25..96d4f027324 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -16,7 +16,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v6
with:
- node-version: '20'
+ node-version: "20"
- name: Checkout code
uses: actions/checkout@v6
@@ -35,6 +35,9 @@ jobs:
- name: Get the diff
run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge | grep '^\(modules\|src\|libraries\|creative\)/.*\.js$' > __changed_files.txt || true
+ - name: Get newly added JS files in TS migration paths
+ run: git diff --name-only --diff-filter=A origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge | grep '^\(modules\|src\|libraries\)/.*\.js$' > __new_js_files.txt || true
+
- name: Run linter on base branch
run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __base.json || true
@@ -56,7 +59,7 @@ jobs:
const fs = require('fs');
const path = require('path');
const process = require('process');
-
+
function parse(fn) {
return JSON.parse(fs.readFileSync(fn)).reduce((memo, data) => {
const file = path.relative(process.cwd(), data.filePath);
@@ -67,7 +70,7 @@ jobs:
return memo;
}, {})
}
-
+
function mkDiff(old, new_) {
const files = Object.fromEntries(
Object.entries(new_)
@@ -83,12 +86,23 @@ jobs:
return memo;
}, {errors: 0, warnings: 0, files})
}
-
- function mkComment({errors, warnings, files}) {
+
+ function mkComment({errors, warnings, files}, newJsFiles) {
function pl(noun, number) {
return noun + (number === 1 ? '' : 's')
}
- if (errors === 0 && warnings === 0) return;
+ const comments = [];
+
+ if (newJsFiles.length > 0) {
+ let jsComment = 'Whoa there partner! This project is migrating to typescript. Consider changing the new JS files to TS, with well-defined types for what interacts with the prebid public API (for example: bid params and configuration). Thanks!\n\n';
+ newJsFiles.forEach((file) => {
+ jsComment += ` * \`${file}\`\n`;
+ });
+ comments.push(jsComment);
+ }
+
+ if (errors === 0 && warnings === 0) return comments.length > 0 ? comments.join('\n') : undefined;
+
const summary = [];
if (errors) summary.push(`**${errors}** linter ${pl('error', errors)}`)
if (warnings) summary.push(`**${warnings}** linter ${pl('warning', warnings)}`)
@@ -99,12 +113,18 @@ jobs:
if (warnings) summary.push(`+${warnings} ${pl('warning', warnings)}`)
cm += ` * \`${file}\` (${summary.join(', ')})\n`
})
- return cm;
+ comments.push(cm);
+ return comments.join('\n');
+ }
+
+ function readLines(fn) {
+ if (!fs.existsSync(fn)) return [];
+ return fs.readFileSync(fn, 'utf8').split('\n').map(line => line.trim()).filter(Boolean);
}
-
+
const [base, pr] = ['__base.json', '__pr.json'].map(parse);
- const comment = mkComment(mkDiff(base, pr));
-
+ const comment = mkComment(mkDiff(base, pr), readLines('__new_js_files.txt'));
+
if (comment) {
fs.writeFileSync("${{ runner.temp }}/comment.json", JSON.stringify({
issue_number: context.issue.number,
diff --git a/AGENTS.md b/AGENTS.md
index 3cfbcda98f4..5bedeec8a9d 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -21,6 +21,7 @@ This file contains instructions for the Codex agent and its friends when working
## General guidance
- Node.js `>=20` is required; dependencies are managed with `npm`.
+- Whenever possible, new modules should provide Typescript types for their public interface.
- Added or modified code must have at least 80% unit test coverage.
- Link any required documentation PRs in the PR description.
- Avoid modifying files in `node_modules` or generated build artifacts under `build`.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b7a797beeb4..8ff2fd54055 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,6 +6,9 @@ master branch.
Pull requests must have 80% code coverage before being considered for merge.
Additional details about the process can be found [here](./PR_REVIEW.md).
+Whenever possible, new modules should provide Typescript types for their public interface.
+Examples of public interface are bid parameters and configuration (including configuration for analytics, userId, or real time data modules).
+
There are more details available if you'd like to contribute a [bid adapter](https://docs.prebid.org/dev-docs/bidder-adaptor.html) or [analytics adapter](https://docs.prebid.org/dev-docs/integrate-with-the-prebid-analytics-api.html).
## Issues
diff --git a/PR_REVIEW.md b/PR_REVIEW.md
index 94fe06c0f0c..75e3e0b35a6 100644
--- a/PR_REVIEW.md
+++ b/PR_REVIEW.md
@@ -19,6 +19,7 @@ General gulp commands include separate commands for serving the codebase on a bu
### General PR review Process
+- Whenever possible, new modules should provide Typescript types for their public interface. Examples of public interface are bid parameters and configuration (including configuration for analytics, userId, or real time data modules).
- All required global and bidder-adapter rules defined in the [Module Rules](https://docs.prebid.org/dev-docs/module-rules.html) must be followed. Please review these rules often - we depend on reviewers to enforce them.
- Checkout the branch (these instructions are available on the GitHub PR page as well).
- Verify PR is a single change type. Example, refactor OR bugfix. If more than 1 type, ask submitter to break out requests.
diff --git a/eslint.config.js b/eslint.config.js
index 90b7313db50..a5310749559 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -202,6 +202,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 @@
-
-
-
-
- } 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/adrelevantisBidAdapter.js b/modules/adrelevantisBidAdapter.js
index 5b28d15a9f3..32b408f73b0 100644
--- a/modules/adrelevantisBidAdapter.js
+++ b/modules/adrelevantisBidAdapter.js
@@ -21,6 +21,7 @@ import { getANKeywordParam } from '../libraries/appnexusUtils/anKeywords.js';
import { chunk } from '../libraries/chunk/chunk.js';
import { transformSizes } from '../libraries/sizeUtils/tranformSize.js';
import { hasUserInfo, hasAppDeviceInfo, hasAppId } from '../libraries/adrelevantisUtils/bidderUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -250,10 +251,9 @@ function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) {
/**
* This function hides google div container for outstream bids to remove unwanted space on page. Appnexus renderer creates a new iframe outside of google iframe to render the outstream creative.
- * @param {string} elementId element id
*/
-function hidedfpContainer(elementId) {
- var el = document.getElementById(elementId).querySelectorAll("div[id^='google_ads']");
+function hidedfpContainer(bid) {
+ var el = getAdUnitElement(bid).querySelectorAll("div[id^='google_ads']");
if (el[0]) {
el[0].style.setProperty('display', 'none');
}
@@ -261,7 +261,7 @@ function hidedfpContainer(elementId) {
function outstreamRender(bid) {
// push to render queue because ANOutstreamVideo may not be loaded yet
- hidedfpContainer(bid.adUnitCode);
+ hidedfpContainer(bid);
bid.renderer.push(() => {
window.ANOutstreamVideo.renderAd({
tagId: bid.adResponse.tag_id,
diff --git a/modules/adtelligentBidAdapter.js b/modules/adtelligentBidAdapter.js
index 589a251a333..00c7bbf72e6 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';
@@ -188,14 +188,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;
}
@@ -238,18 +230,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..a4badd11a4c 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 b81dd579329..9fdb1c051c4 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 62beb22c521..9611cd93521 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 a4ec0d833cd..e4d19055ce0 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 74d24afecf9..cad4bd0c948 100644
--- a/modules/appnexusBidAdapter.js
+++ b/modules/appnexusBidAdapter.js
@@ -21,21 +21,21 @@ 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';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -295,10 +295,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 +346,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 => {
@@ -613,7 +597,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,
@@ -623,17 +607,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];
@@ -935,11 +908,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);
}
@@ -1155,14 +1124,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;
@@ -1176,54 +1137,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);
}
@@ -1266,11 +1179,10 @@ function buildNativeRequest(params) {
/**
* This function hides google div container for outstream bids to remove unwanted space on page. Appnexus renderer creates a new iframe outside of google iframe to render the outstream creative.
- * @param {string} elementId element id
*/
-function hidedfpContainer(elementId) {
+function hidedfpContainer(container) {
try {
- const el = document.getElementById(elementId).querySelectorAll("div[id^='google_ads']");
+ const el = container.querySelectorAll("div[id^='google_ads']");
if (el[0]) {
el[0].style.setProperty('display', 'none');
}
@@ -1279,10 +1191,10 @@ function hidedfpContainer(elementId) {
}
}
-function hideSASIframe(elementId) {
+function hideSASIframe(container) {
try {
// find script tag with id 'sas_script'. This ensures it only works if you're using Smart Ad Server.
- const el = document.getElementById(elementId).querySelectorAll("script[id^='sas_script']");
+ const el = container.querySelectorAll("script[id^='sas_script']");
if (el[0].nextSibling && el[0].nextSibling.localName === 'iframe') {
el[0].nextSibling.style.setProperty('display', 'none');
}
@@ -1292,8 +1204,9 @@ function hideSASIframe(elementId) {
}
function outstreamRender(bid, doc) {
- hidedfpContainer(bid.adUnitCode);
- hideSASIframe(bid.adUnitCode);
+ const container = getAdUnitElement(bid);
+ hidedfpContainer(container);
+ hideSASIframe(container);
// push to render queue because ANOutstreamVideo may not be loaded yet
bid.renderer.push(() => {
const win = doc?.defaultView || window;
diff --git a/modules/apstreamBidAdapter.js b/modules/apstreamBidAdapter.js
index 68f391e106d..32c5f8242ec 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 58ca7cec914..43c0643e394 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 a621eedeabc..5c51167b63e 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 c1160567d80..f85c233e644 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/bidViewability.js b/modules/bidViewability.js
index 2670f601a24..191df92f8f6 100644
--- a/modules/bidViewability.js
+++ b/modules/bidViewability.js
@@ -3,82 +3,34 @@
// Does not work with other than GPT integration
import { config } from '../src/config.js';
-import * as events from '../src/events.js';
-import { EVENTS } from '../src/constants.js';
-import { isFn, logWarn, triggerPixel } from '../src/utils.js';
+import { isAdUnitCodeMatchingSlot, logWarn } from '../src/utils.js';
import { getGlobal } from '../src/prebidGlobal.js';
-import adapterManager, { gppDataHandler, uspDataHandler } from '../src/adapterManager.js';
-import { gdprParams } from '../libraries/dfpUtils/dfpUtils.js';
+import { triggerBidViewable } from '../libraries/bidViewabilityPixels/index.js';
const MODULE_NAME = 'bidViewability';
const CONFIG_ENABLED = 'enabled';
-const CONFIG_FIRE_PIXELS = 'firePixels';
-const CONFIG_CUSTOM_MATCH = 'customMatchFunction';
-const BID_VURL_ARRAY = 'vurls';
const GPT_IMPRESSION_VIEWABLE_EVENT = 'impressionViewable';
-export const isBidAdUnitCodeMatchingSlot = (bid, slot) => {
- return (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode);
-}
-
-export const getMatchingWinningBidForGPTSlot = (globalModuleConfig, slot) => {
+export const getMatchingWinningBidForGPTSlot = (slot) => {
+ const match = isAdUnitCodeMatchingSlot(slot);
return getGlobal().getAllWinningBids().find(
// supports custom match function from config
- bid => isFn(globalModuleConfig[CONFIG_CUSTOM_MATCH])
- ? globalModuleConfig[CONFIG_CUSTOM_MATCH](bid, slot)
- : isBidAdUnitCodeMatchingSlot(bid, slot)
+ ({ adUnitCode }) => match(adUnitCode)
) || null;
};
-export const fireViewabilityPixels = (globalModuleConfig, bid) => {
- if (globalModuleConfig[CONFIG_FIRE_PIXELS] === true && bid.hasOwnProperty(BID_VURL_ARRAY)) {
- const queryParams = gdprParams();
-
- const uspConsent = uspDataHandler.getConsentData();
- if (uspConsent) { queryParams.us_privacy = uspConsent; }
-
- const gppConsent = gppDataHandler.getConsentData();
- if (gppConsent) {
- // TODO - need to know what to set here for queryParams...
- }
-
- bid[BID_VURL_ARRAY].forEach(url => {
- // add '?' if not present in URL
- if (Object.keys(queryParams).length > 0 && url.indexOf('?') === -1) {
- url += '?';
- }
- // append all query params, `&key=urlEncoded(value)`
- url += Object.keys(queryParams).reduce((prev, key) => {
- prev += `&${key}=${encodeURIComponent(queryParams[key])}`;
- return prev;
- }, '');
- triggerPixel(url)
- });
- }
-};
-
export const logWinningBidNotFound = (slot) => {
logWarn(`bid details could not be found for ${slot.getSlotElementId()}, probable reasons: a non-prebid bid is served OR check the prebid.AdUnit.code to GPT.AdSlot relation.`);
};
export const impressionViewableHandler = (globalModuleConfig, event) => {
const slot = event.slot;
- const respectiveBid = getMatchingWinningBidForGPTSlot(globalModuleConfig, slot);
+ const respectiveBid = getMatchingWinningBidForGPTSlot(slot);
if (respectiveBid === null) {
logWinningBidNotFound(slot);
} else {
- // if config is enabled AND VURL array is present then execute each pixel
- fireViewabilityPixels(globalModuleConfig, respectiveBid);
- // trigger respective bidder's onBidViewable handler
- adapterManager.callBidViewableBidder(respectiveBid.adapterCode || respectiveBid.bidder, respectiveBid);
-
- if (respectiveBid.deferBilling) {
- adapterManager.triggerBilling(respectiveBid);
- }
-
- // emit the BID_VIEWABLE event with bid details, this event can be consumed by bidders and analytics pixels
- events.emit(EVENTS.BID_VIEWABLE, respectiveBid);
+ triggerBidViewable(respectiveBid);
}
};
@@ -90,7 +42,6 @@ const handleSetConfig = (config) => {
// do nothing if module-config.enabled is not set to true
// this way we are adding a way for bidders to know (using pbjs.getConfig('bidViewability').enabled === true) whether this module is added in build and is enabled
const impressionViewableHandlerWrapper = (event) => {
- window.googletag.pubads().removeEventListener(GPT_IMPRESSION_VIEWABLE_EVENT, impressionViewableHandlerWrapper);
impressionViewableHandler(globalModuleConfig, event);
};
@@ -102,6 +53,7 @@ const handleSetConfig = (config) => {
}
// add the GPT event listener
window.googletag.cmd.push(() => {
+ window.googletag.pubads().removeEventListener(GPT_IMPRESSION_VIEWABLE_EVENT, impressionViewableHandlerWrapper);
window.googletag.pubads().addEventListener(GPT_IMPRESSION_VIEWABLE_EVENT, impressionViewableHandlerWrapper);
});
}
diff --git a/modules/bidViewability.md b/modules/bidViewability.md
index 922a4a9def4..24f7dcd019e 100644
--- a/modules/bidViewability.md
+++ b/modules/bidViewability.md
@@ -12,7 +12,7 @@ Maintainer: harshad.mane@pubmatic.com
- GPT API is used to find when a bid is viewable, https://developers.google.com/publisher-tag/reference#googletag.events.impressionviewableevent . This event is fired when an impression becomes viewable, according to the Active View criteria.
Refer: https://support.google.com/admanager/answer/4524488
- This module does not work with any adserver's other than GAM with GPT integration
-- Logic used to find a matching pbjs-bid for a GPT slot is ``` (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) ``` this logic can be changed by using param ```customMatchFunction```
+- Logic used to find a matching pbjs-bid for a GPT slot is ``` (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) ``` this logic can be changed by using config param ```customGptSlotMatching```
- When a rendered PBJS bid is viewable the module will trigger a BID_VIEWABLE event, which can be consumed by bidders and analytics adapters
- If the viewable bid contains a ```vurls``` param containing URL's and the Bid Viewability module is configured with ``` firePixels: true ``` then the URLs mentioned in bid.vurls will be called. Please note that GDPR and USP related parameters will be added to the given URLs
- This module is also compatible with Prebid core's billing deferral logic, this means that bids linked to an ad unit marked with `deferBilling: true` will trigger a bid adapter's `onBidBillable` function (if present) indicating an ad slot was viewed and also billing ready (if it were deferred).
@@ -20,7 +20,6 @@ Refer: https://support.google.com/admanager/answer/4524488
# Params
- enabled [required] [type: boolean, default: false], when set to true, the module will emit BID_VIEWABLE when applicable
- firePixels [optional] [type: boolean], when set to true, will fire the urls mentioned in bid.vurls which should be array of urls
-- customMatchFunction [optional] [type: function(bid, slot)], when passed this function will be used to `find` the matching winning bid for the GPT slot. Default value is ` (bid, slot) => (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) `
# Example of consuming BID_VIEWABLE event
```
diff --git a/modules/bidViewabilityIO.js b/modules/bidViewabilityIO.js
index 0e54d969b81..34dc03c168f 100644
--- a/modules/bidViewabilityIO.js
+++ b/modules/bidViewabilityIO.js
@@ -2,6 +2,8 @@ import { logMessage } from '../src/utils.js';
import { config } from '../src/config.js';
import * as events from '../src/events.js';
import { EVENTS } from '../src/constants.js';
+import { triggerBidViewable } from '../libraries/bidViewabilityPixels/index.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const MODULE_NAME = 'bidViewabilityIO';
const CONFIG_ENABLED = 'enabled';
@@ -42,7 +44,7 @@ export const getViewableOptions = (bid) => {
export const markViewed = (bid, entry, observer) => {
return () => {
observer.unobserve(entry.target);
- events.emit(EVENTS.BID_VIEWABLE, bid);
+ triggerBidViewable(bid);
_logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} was viewed`);
}
}
@@ -80,7 +82,7 @@ export const init = () => {
events.on(EVENTS.AD_RENDER_SUCCEEDED, ({ doc, bid, id }) => {
if (isSupportedMediaType(bid)) {
const viewable = new IntersectionObserver(viewCallbackFactory(bid), getViewableOptions(bid));
- const element = document.getElementById(bid.adUnitCode);
+ const element = getAdUnitElement(bid);
viewable.observe(element);
}
});
diff --git a/modules/bmtmBidAdapter.js b/modules/bmtmBidAdapter.js
index 36c5c3c89ca..a5663d35299 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 741bc0db16b..fa8a283b924 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 a1925921e44..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 3bb60cef907..68e30854916 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 31c2c7bf342..920c4670b84 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..93c031dcdf7 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/concertBidAdapter.js b/modules/concertBidAdapter.js
index a83c078ccef..e9d463ca937 100644
--- a/modules/concertBidAdapter.js
+++ b/modules/concertBidAdapter.js
@@ -4,6 +4,7 @@ import { getStorageManager } from '../src/storageManager.js';
import { hasPurpose1Consent } from '../src/utils/gdpr.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { getViewportCoordinates } from '../libraries/viewport/viewport.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -70,7 +71,7 @@ export const spec = {
payload.slots = validBidRequests.map((bidRequest) => {
eids.push(...(bidRequest.userIdAsEids || []));
- const adUnitElement = document.getElementById(bidRequest.adUnitCode);
+ const adUnitElement = getAdUnitElement(bidRequest);
const coordinates = getOffset(adUnitElement);
const slot = {
diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js
index 3d61234444c..c8364b97daa 100644
--- a/modules/connatixBidAdapter.js
+++ b/modules/connatixBidAdapter.js
@@ -25,6 +25,7 @@ import {
BANNER,
VIDEO,
} from '../src/mediaTypes.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'connatix';
@@ -124,7 +125,7 @@ function getDomElement(elementId) {
}
export function detectViewability(bid) {
- const { params, adUnitCode } = bid;
+ const { params } = bid;
const viewabilityContainerIdentifier = params.viewabilityContainerIdentifier;
@@ -151,7 +152,7 @@ export function detectViewability(bid) {
bidParamSizes = typeof bidParamSizes === 'undefined' && bid.mediaType && bid.mediaType.video && bid.mediaType.video.playerSize ? bid.mediaType.video.playerSize : bidParamSizes;
bidParamSizes = typeof bidParamSizes === 'undefined' && bid.mediaType && bid.mediaType.video && isNumber(bid.mediaType.video.w) && isNumber(bid.mediaType.h) ? [bid.mediaType.video.w, bid.mediaType.video.h] : bidParamSizes;
minSize = _getMinSize(bidParamSizes ?? [])
- element = document.getElementById(adUnitCode);
+ element = getAdUnitElement(bid);
}
if (isViewabilityMeasurable(element)) {
diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js
index 71f8986e604..d1fec831b50 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/contxtfulRtdProvider.js b/modules/contxtfulRtdProvider.js
index 4c319c9b48a..f711c300b8b 100644
--- a/modules/contxtfulRtdProvider.js
+++ b/modules/contxtfulRtdProvider.js
@@ -292,6 +292,7 @@ function getDivIdPosition(divId) {
let domElement;
+ // TODO: this should use getAdUnitElement
if (inIframe() === true) {
const ws = getWindowSelf();
const currentElement = ws.document.getElementById(divId);
@@ -335,6 +336,7 @@ function tryGetDivIdPosition(divIdMethod) {
return undefined;
}
+// TODO unified adUnit/element association in 11
function tryMultipleDivIdPositions(adUnit) {
const divMethods = [
// ortb2\
diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js
index a6ef6ba26e6..56fc19ef7be 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/cwireBidAdapter.js b/modules/cwireBidAdapter.js
index 875dfdedf67..46647b31c58 100644
--- a/modules/cwireBidAdapter.js
+++ b/modules/cwireBidAdapter.js
@@ -11,6 +11,7 @@ import { getBoundingClientRect } from "../libraries/boundingClientRect/boundingC
import { hasPurpose1Consent } from "../src/utils/gdpr.js";
import { sendBeacon } from "../src/ajax.js";
import { isAutoplayEnabled } from "../libraries/autoplayDetection/autoplay.js";
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -35,7 +36,7 @@ export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
*/
function slotDimensions(bid) {
const adUnitCode = bid.adUnitCode;
- const slotEl = document.getElementById(adUnitCode);
+ const slotEl = getAdUnitElement(bid);
if (slotEl) {
logInfo(`Slot element found: ${adUnitCode}`);
diff --git a/modules/debugging/bidInterceptor.js b/modules/debugging/bidInterceptor.js
index a6b452d2d91..afd644684d7 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 5413ca37082..022d901264d 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 484e99dcd5f..da246f30511 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 0d5d2bb6435..47602bd218f 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 d9e038d58d2..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 4f547ececfa..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 704069783bc..0c56118dc71 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 02982b27a82..a2eea9e9130 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/dmdIdSystem.js b/modules/dmdIdSystem.js
deleted file mode 100644
index 4fc986bd1fc..00000000000
--- a/modules/dmdIdSystem.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * This module adds dmdId to the User ID module
- * The {@link module:modules/userId} module is required
- * @module modules/dmdIdSystem
- * @requires module:modules/userId
- */
-
-import { logError, getWindowLocation } from '../src/utils.js';
-import { submodule } from '../src/hook.js';
-import { ajax } from '../src/ajax.js';
-
-/**
- * @typedef {import('../modules/userId/index.js').Submodule} Submodule
- * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
- * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
- * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
- */
-
-const MODULE_NAME = 'dmdId';
-
-/** @type {Submodule} */
-export const dmdIdSubmodule = {
- /**
- * used to link submodule with config
- * @type {string}
- */
- name: MODULE_NAME,
-
- /**
- * decode the stored id value for passing to bid requests
- * @function decode
- * @param {(Object|string)} value
- * @returns {(Object|undefined)}
- */
- decode(value) {
- return value && typeof value === 'string'
- ? { 'dmdId': value }
- : undefined;
- },
-
- /**
- * performs action to obtain id and return a value in the callback's response argument
- * @function getId
- * @param {SubmoduleConfig} [config]
- * @param {ConsentData} consentData
- * @param {Object} cacheIdObj - existing id, if any
- * @returns {IdResponse|undefined}
- */
- getId(config, consentData, cacheIdObj) {
- const configParams = (config && config.params) || {};
- if (
- !configParams ||
- !configParams.api_key ||
- typeof configParams.api_key !== 'string'
- ) {
- logError('dmd submodule requires an api_key.');
- return;
- }
- // If cahceIdObj is null or undefined - calling AIX-API
- if (cacheIdObj) {
- return cacheIdObj;
- } else {
- const url = configParams && configParams.api_url
- ? configParams.api_url
- : `https://aix.hcn.health/api/v1/auths`;
- // Setting headers
- const headers = {};
- headers['x-api-key'] = configParams.api_key;
- headers['x-domain'] = getWindowLocation();
- // Response callbacks
- const resp = function (callback) {
- const callbacks = {
- success: response => {
- let responseObj;
- let responseId;
- try {
- responseObj = JSON.parse(response);
- if (responseObj && responseObj.dgid) {
- responseId = responseObj.dgid;
- }
- } catch (error) {
- logError(error);
- }
- callback(responseId);
- },
- error: error => {
- logError(`${MODULE_NAME}: ID fetch encountered an error`, error);
- callback();
- }
- };
- ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true, customHeaders: headers });
- };
- return { callback: resp };
- }
- },
- eids: {
- 'dmdId': {
- source: 'hcn.health',
- atype: 3
- },
- }
-};
-
-submodule('userId', dmdIdSubmodule);
diff --git a/modules/dmdIdSystem.md b/modules/dmdIdSystem.md
deleted file mode 100644
index f2a5b76ade7..00000000000
--- a/modules/dmdIdSystem.md
+++ /dev/null
@@ -1,26 +0,0 @@
-pbjs.setConfig({
- userSync: {
- userIds: [{
- name: 'dmdId',
- storage: {
- name: 'dmd-dgid',
- type: 'cookie',
- expires: 30
- },
- params: {
- api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c', // provided by DMD
- }
- }]
- }
-});
-
-#### DMD ID Configuration
-
-{: .table .table-bordered .table-striped }
-| Param under userSync.userIds[] | Scope | Type | Description | Example |
-| --- | --- | --- | --- | --- |
-| name | Required | String | The name of Module | `"dmdId"` |
-| storage | Required | Object | |
-| storage.name | Required | String | `dmd-dgid` |
-| params | Required | Object | Container of all module params. | |
-| params.api_key | Required | String | This is your `api_key` as provided by DMD Marketing Corp. | `3fdbe297-3690-4f5c-9e11-ee9186a6d77c` |
\ No newline at end of file
diff --git a/modules/empowerBidAdapter.js b/modules/empowerBidAdapter.js
index 14e8be2a82d..919305f5519 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/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js
index 12e643402d6..27f5171e724 100644
--- a/modules/eplanningBidAdapter.js
+++ b/modules/eplanningBidAdapter.js
@@ -420,6 +420,7 @@ function _mapAdUnitPathToElementId(adUnitCode) {
}
function _getAdSlotHTMLElement(adUnitCode) {
+ // TODO: this should use getAdUnitElement
return document.getElementById(adUnitCode) ||
document.getElementById(_mapAdUnitPathToElementId(adUnitCode));
}
diff --git a/modules/express.js b/modules/express.js
deleted file mode 100644
index 760a6f578e5..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/fanBidAdapter.js b/modules/fanBidAdapter.js
index d4b2954d9d2..a3690cd6098 100644
--- a/modules/fanBidAdapter.js
+++ b/modules/fanBidAdapter.js
@@ -6,6 +6,7 @@ import { getBidFloor } from '../libraries/currencyUtils/floor.js';
import { getStorageManager } from '../src/storageManager.js';
import { Renderer } from '../src/Renderer.js';
import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'freedomadnetwork';
const BIDDER_VERSION = '0.2.0';
@@ -349,8 +350,7 @@ function createRenderer(bid, videoPlayerUrl) {
try {
renderer.setRender(function (bidResponse) {
- const divId = document.getElementById(bid.adUnitCode) ? bid.adUnitCode : getGptSlotInfoForAdUnitCode(bid.adUnitCode).divId;
- const adUnit = document.getElementById(divId);
+ const adUnit = getAdUnitElement(bidResponse) ?? document.getElementById(getGptSlotInfoForAdUnitCode(bid.adUnitCode).divId)
if (!window.createOutstreamPlayer) {
logWarn('Renderer error: outstream player is not available');
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 5f52c935554..3fc5dddd678 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 {
@@ -199,12 +198,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 8aebb860c48..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/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js
index a8611176e10..f1ae1d1aab4 100644
--- a/modules/gamoshiBidAdapter.js
+++ b/modules/gamoshiBidAdapter.js
@@ -16,6 +16,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { ortb25Translator } from '../libraries/ortb2.5Translator/translator.js';
import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const ENDPOINTS = {
'gamoshi': 'https://rtb.gamoshi.io',
'cleanmedianet': 'https://bidder.cleanmediaads.com'
@@ -250,7 +251,7 @@ function renderOutstream(bid) {
window['GamoshiPlayer'].renderAd({
id: unitId,
debug: window.location.href.indexOf('pbjsDebug') >= 0,
- placement: document.getElementById(bid.adUnitCode),
+ placement: getAdUnitElement(bid),
width: bid.width,
height: bid.height,
events: {
diff --git a/modules/gmosspBidAdapter.js b/modules/gmosspBidAdapter.js
index c043e852831..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/gptPreAuction.ts b/modules/gptPreAuction.ts
index 3c9b071098e..5bfb9d243a0 100644
--- a/modules/gptPreAuction.ts
+++ b/modules/gptPreAuction.ts
@@ -13,8 +13,6 @@ import {
pick,
uniques
} from '../src/utils.js';
-import type { SlotMatchingFn } from '../src/targeting.ts';
-import type { AdUnitCode } from '../src/types/common.d.ts';
import type { AdUnit } from '../src/adUnits.ts';
const MODULE_NAME = 'GPT Pre-Auction';
@@ -66,8 +64,6 @@ export function getAuctionsIdsFromTargeting(targeting, am = auctionManager) {
}
export const appendGptSlots = adUnits => {
- const { customGptSlotMatching } = _currentConfig;
-
if (!isGptPubadsDefined()) {
return;
}
@@ -81,9 +77,7 @@ export const appendGptSlots = adUnits => {
const adUnitPaths = {};
window.googletag.pubads().getSlots().forEach((slot: googletag.Slot) => {
- const matchingAdUnitCode = Object.keys(adUnitMap).find(customGptSlotMatching
- ? customGptSlotMatching(slot)
- : isAdUnitCodeMatchingSlot(slot));
+ const matchingAdUnitCode = Object.keys(adUnitMap).find(isAdUnitCodeMatchingSlot(slot));
if (matchingAdUnitCode) {
const path = adUnitPaths[matchingAdUnitCode] = slot.getAdUnitPath();
@@ -174,16 +168,9 @@ type GPTPreAuctionConfig = {
*/
enabled?: boolean;
/**
- * If true, use default behavior for determining GPID and PbAdSlot. Defaults to false.
+ * If true, use default behavior for determining GPID. Defaults to false.
*/
useDefaultPreAuction?: boolean;
- customGptSlotMatching?: SlotMatchingFn;
- /**
- * @param adUnitCode Ad unit code
- * @param adServerAdSlot The value of that ad unit's `ortb2Imp.ext.data.adserver.adslot`
- * @returns pbadslot for the ad unit
- */
- customPbAdSlot?: (adUnitCode: AdUnitCode, adServerAdSlot: string) => string;
/**
* @param adUnit An ad unit object
* @param adServerAdSlot The value of that ad unit's `ortb2Imp.ext.data.adserver.adslot`
@@ -206,8 +193,6 @@ declare module '../src/config' {
const handleSetGptConfig = moduleConfig => {
_currentConfig = pick(moduleConfig, [
'enabled', enabled => enabled !== false,
- 'customGptSlotMatching', customGptSlotMatching =>
- typeof customGptSlotMatching === 'function' && customGptSlotMatching,
'customPreAuction', customPreAuction => typeof customPreAuction === 'function' && customPreAuction,
'useDefaultPreAuction', useDefaultPreAuction => useDefaultPreAuction ?? true,
]);
diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js
index 93d9a2b10dd..e49c23bbf27 100644
--- a/modules/growthCodeAnalyticsAdapter.js
+++ b/modules/growthCodeAnalyticsAdapter.js
@@ -93,11 +93,6 @@ const growthCodeAnalyticsAdapter = Object.assign(adapter({ url: url, analyticsTy
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 316a5401da9..6aca8a36728 100644
--- a/modules/gumgumBidAdapter.js
+++ b/modules/gumgumBidAdapter.js
@@ -1,11 +1,13 @@
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { _each, deepAccess, getWinDimensions, logError, logWarn, parseSizesInput } from '../src/utils.js';
+import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRatio.js';
import { config } from '../src/config.js';
-import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js';
-import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRatio.js';
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
@@ -279,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,
@@ -303,78 +305,6 @@ function _getDeviceData(ortb2Data) {
}, {});
}
-/**
- * Retrieves content metadata from the ORTB2 object
- * Supports both site.content and app.content (site takes priority)
- * @param {Object} ortb2Data ORTB2 object
- * @returns {Object} Content parameters
- */
-function _getContentParams(ortb2Data) {
- // Check site.content first, then app.content
- const siteContent = deepAccess(ortb2Data, 'site.content');
- const appContent = deepAccess(ortb2Data, 'app.content');
- const content = siteContent || appContent;
-
- if (!content) {
- return {};
- }
-
- const contentParams = {};
- contentParams.itype = siteContent ? 'site' : 'app';
-
- // Basic content fields
- if (content.id) contentParams.cid = content.id;
- if (content.episode !== undefined && content.episode !== null) contentParams.cepisode = content.episode;
- if (content.title) contentParams.ctitle = content.title;
- if (content.series) contentParams.cseries = content.series;
- if (content.season) contentParams.cseason = content.season;
- if (content.genre) contentParams.cgenre = content.genre;
- if (content.contentrating) contentParams.crating = content.contentrating;
- if (content.userrating) contentParams.cur = content.userrating;
- if (content.context !== undefined && content.context !== null) contentParams.cctx = content.context;
- if (content.livestream !== undefined && content.livestream !== null) contentParams.clive = content.livestream;
- if (content.len !== undefined && content.len !== null) contentParams.clen = content.len;
- if (content.language) contentParams.clang = content.language;
- if (content.url) contentParams.curl = content.url;
- if (content.cattax !== undefined && content.cattax !== null) contentParams.cattax = content.cattax;
- if (content.prodq !== undefined && content.prodq !== null) contentParams.cprodq = content.prodq;
- if (content.qagmediarating !== undefined && content.qagmediarating !== null) contentParams.cqag = content.qagmediarating;
-
- // Handle keywords - can be string or array
- if (content.keywords) {
- if (Array.isArray(content.keywords)) {
- contentParams.ckw = content.keywords.join(',');
- } else if (typeof content.keywords === 'string') {
- contentParams.ckw = content.keywords;
- }
- }
-
- // Handle cat array
- if (content.cat && Array.isArray(content.cat) && content.cat.length > 0) {
- contentParams.ccat = content.cat.join(',');
- }
-
- // Handle producer fields
- if (content.producer) {
- if (content.producer.id) contentParams.cpid = content.producer.id;
- if (content.producer.name) contentParams.cpname = content.producer.name;
- }
-
- // Channel fields
- if (content.channel) {
- if (content.channel.id) contentParams.cchannelid = content.channel.id;
- if (content.channel.name) contentParams.cchannel = content.channel.name;
- if (content.channel.domain) contentParams.cchanneldomain = content.channel.domain;
- }
-
- // Network fields
- if (content.network) {
- if (content.network.name) contentParams.cnetwork = content.network.name;
- }
-
- return contentParams;
-}
-
/**
* loops through bannerSizes array to get greatest slot dimensions
* @param {number[][]} sizes
@@ -397,53 +327,28 @@ function getGreatestDimensions(sizes) {
return [maxw, maxh];
}
-function getFirstUid(eid) {
- if (!eid || !Array.isArray(eid.uids)) return null;
- return eid.uids.find(uid => uid && uid.id);
-}
-
-function getUserEids(bidRequest, bidderRequest) {
- const bidderRequestEids = deepAccess(bidderRequest, 'ortb2.user.ext.eids');
- if (Array.isArray(bidderRequestEids) && bidderRequestEids.length) {
- return bidderRequestEids;
- }
- const bidEids = deepAccess(bidRequest, 'userIdAsEids');
- if (Array.isArray(bidEids) && bidEids.length) {
- return bidEids;
- }
- const bidUserEids = deepAccess(bidRequest, 'user.ext.eids');
- if (Array.isArray(bidUserEids) && bidUserEids.length) {
- return bidUserEids;
- }
- return [];
-}
-
-function isPubProvidedIdEid(eid) {
- const source = (eid && eid.source) ? eid.source.toLowerCase() : '';
- if (!source || !pubProvidedIdSources.includes(source) || !Array.isArray(eid.uids)) return false;
- return eid.uids.some(uid => uid && uid.ext && uid.ext.stype);
-}
-
-function getEidsFromEidsArray(eids) {
- return (Array.isArray(eids) ? eids : []).reduce((ids, eid) => {
- const source = (eid.source || '').toLowerCase();
- if (source === 'uidapi.com') {
- const uid = getFirstUid(eid);
- if (uid) {
- ids.uid2 = uid.id;
- }
- } else if (source === 'liveramp.com') {
- const uid = getFirstUid(eid);
- if (uid) {
- ids.idl_env = uid.id;
- }
- } else if (source === 'adserver.org' && Array.isArray(eid.uids)) {
- const tdidUid = eid.uids.find(uid => uid && uid.id && uid.ext && uid.ext.rtiPartner === 'TDID');
- if (tdidUid) {
- ids.tdid = tdidUid.id;
- }
+function getEids(userId) {
+ const idProperties = [
+ 'uid',
+ 'eid',
+ 'lipbid',
+ 'envelope',
+ 'id'
+ ];
+
+ return Object.keys(userId).reduce(function (eids, provider) {
+ const eid = userId[provider];
+ switch (typeof eid) {
+ case 'string':
+ eids[provider] = eid;
+ break;
+
+ case 'object':
+ const idProp = idProperties.filter(prop => eid.hasOwnProperty(prop));
+ idProp.length && (eids[provider] = eid[idProp[0]]);
+ break;
}
- return ids;
+ return eids;
}, {});
}
@@ -467,14 +372,13 @@ function buildRequests(validBidRequests, bidderRequest) {
bidId,
mediaTypes = {},
params = {},
+ userId = {},
ortb2Imp,
adUnitCode = ''
} = bidRequest;
const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest);
- const userEids = getUserEids(bidRequest, bidderRequest);
- const eids = getEidsFromEidsArray(userEids);
+ 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';
@@ -497,20 +401,16 @@ function buildRequests(validBidRequests, bidderRequest) {
}
}
// Send filtered pubProvidedId's
- if (userEids.length) {
- const filteredData = userEids.filter(isPubProvidedIdEid);
+ if (userId && userId.pubProvidedId) {
+ const filteredData = userId.pubProvidedId.filter(item => pubProvidedIdSources.includes(item.source));
const maxLength = 1800; // replace this with your desired maximum length
const truncatedJsonString = jsoStringifynWithMaxLength(filteredData, maxLength);
- if (filteredData.length) {
- data.pubProvidedId = truncatedJsonString
- }
+ data.pubProvidedId = truncatedJsonString
}
// ADJS-1286 Read id5 id linktype field
- const id5Eid = userEids.find(eid => (eid.source || '').toLowerCase() === 'id5-sync.com');
- const id5Uid = getFirstUid(id5Eid);
- if (id5Uid && id5Uid.ext) {
- data.id5Id = id5Uid.id || null
- data.id5IdLinkType = id5Uid.ext.linkType || null
+ if (userId && userId.id5id && userId.id5id.uid && userId.id5id.ext) {
+ data.id5Id = userId.id5id.uid || null
+ data.id5IdLinkType = userId.id5id.ext.linkType || null
}
// ADTS-169 add adUnitCode to requests
if (adUnitCode) data.aun = adUnitCode;
@@ -538,10 +438,9 @@ function buildRequests(validBidRequests, bidderRequest) {
}
if (bidderRequest && bidderRequest.ortb2 && bidderRequest.ortb2.site) {
setIrisId(data, bidderRequest.ortb2.site, params);
+ const curl = bidderRequest.ortb2.site.content?.url;
+ if (curl) data.curl = curl;
}
- // Extract content metadata from ortb2
- const contentParams = _getContentParams(bidderRequest?.ortb2);
- Object.assign(data, contentParams);
if (params.iriscat && typeof params.iriscat === 'string') {
data.iriscat = params.iriscat;
}
@@ -568,9 +467,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/h12mediaBidAdapter.js b/modules/h12mediaBidAdapter.js
index 63e00622176..90b284a485c 100644
--- a/modules/h12mediaBidAdapter.js
+++ b/modules/h12mediaBidAdapter.js
@@ -2,6 +2,7 @@ import { inIframe, logError, logMessage, deepAccess, getWinDimensions } from '..
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { getViewportSize } from '../libraries/viewport/viewport.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'h12media';
const DEFAULT_URL = 'https://bidder.h12-media.com/prebid/';
const DEFAULT_CURRENCY = 'USD';
@@ -30,7 +31,7 @@ export const spec = {
pubsubid = '';
}
const pubcontainerid = bidderParams.pubcontainerid;
- const adUnitElement = document.getElementById(pubcontainerid || bidRequest.adUnitCode);
+ const adUnitElement = pubcontainerid ? document.getElementById(pubcontainerid) : getAdUnitElement(bidRequest);
const ishidden = !isVisible(adUnitElement);
const framePos = getFramePos();
const coords = isiframe ? {
diff --git a/modules/hadronAnalyticsAdapter.js b/modules/hadronAnalyticsAdapter.js
index 37c1478fcb8..dae64cd0e5b 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/hypelabBidAdapter.js b/modules/hypelabBidAdapter.js
index bc562b84cb3..2112d93b9e5 100644
--- a/modules/hypelabBidAdapter.js
+++ b/modules/hypelabBidAdapter.js
@@ -5,6 +5,7 @@ import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRa
import { ajax } from '../src/ajax.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { getWalletPresence, getWalletProviderFlags } from '../libraries/hypelabUtils/hypelabUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
export const BIDDER_CODE = 'hypelab';
export const ENDPOINT_URL = 'https://api.hypelab.com';
@@ -55,7 +56,7 @@ function buildRequests(validBidRequests, bidderRequest) {
winDimensions?.innerHeight || 0
),
];
- const pp = getPosition(request.adUnitCode);
+ const pp = getPosition(request);
const payload = {
property_slug: request.params.property_slug,
@@ -121,8 +122,8 @@ function getBidFloor(bid, sizes) {
return floor;
}
-function getPosition(id) {
- const element = document.getElementById(id);
+function getPosition(bidRequest) {
+ const element = getAdUnitElement(bidRequest);
if (!element) return null;
const rect = getBoundingClientRect(element);
return [rect.left, rect.top];
diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js
index 8ecdca972d3..14a35d318f5 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/intersectionRtdProvider.js b/modules/intersectionRtdProvider.js
deleted file mode 100644
index b57fd919d16..00000000000
--- a/modules/intersectionRtdProvider.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import { submodule } from '../src/hook.js';
-import { isFn, logError } from '../src/utils.js';
-import { config } from '../src/config.js';
-import { getGlobal } from '../src/prebidGlobal.js';
-
-import '../src/adapterManager.js';
-
-let observerAvailable = true;
-function getIntersectionData(requestBidsObject, onDone, providerConfig, userConsent) {
- const intersectionMap = {};
- const placeholdersMap = {};
- let done = false;
- if (!observerAvailable) return complete();
- const observer = new IntersectionObserver(observerCallback, { threshold: 0.5 });
- const adUnitCodes = requestBidsObject.adUnitCodes || [];
- const auctionDelay = config.getConfig('realTimeData.auctionDelay') || 0;
- const waitForIt = providerConfig.waitForIt;
- let adUnits = requestBidsObject.adUnits || getGlobal().adUnits || [];
- if (adUnitCodes.length) {
- adUnits = adUnits.filter(unit => adUnitCodes.includes(unit.code));
- }
- let checkTimeoutId;
- findAndObservePlaceholders();
- if (auctionDelay > 0) {
- setTimeout(complete, auctionDelay);
- }
- function findAndObservePlaceholders() {
- const observed = adUnits.filter((unit) => {
- const code = unit.code;
- if (placeholdersMap[code]) return true;
- const ph = document.getElementById(code);
- if (ph) {
- placeholdersMap[code] = ph;
- observer.observe(ph);
- return true;
- }
- return false;
- });
- if (
- observed.length === adUnits.length ||
- !waitForIt ||
- auctionDelay <= 0
- ) {
- return;
- }
- checkTimeoutId = setTimeout(findAndObservePlaceholders);
- }
- function observerCallback(entries) {
- let entry = entries.pop();
- while (entry) {
- const target = entry.target;
- const id = target.getAttribute('id');
- if (id) {
- const intersection = intersectionMap[id];
- if (!intersection || intersection.time < entry.time) {
- intersectionMap[id] = {
- 'boundingClientRect': cloneRect(entry.boundingClientRect),
- 'intersectionRect': cloneRect(entry.intersectionRect),
- 'rootRect': cloneRect(entry.rootRect),
- 'intersectionRatio': entry.intersectionRatio,
- 'isIntersecting': entry.isIntersecting,
- 'time': entry.time
- };
- if (adUnits.every(unit => !!intersectionMap[unit.code])) {
- complete();
- }
- }
- }
- entry = entries.pop();
- }
- }
- function complete() {
- if (done) return;
- if (checkTimeoutId) clearTimeout(checkTimeoutId);
- done = true;
- checkTimeoutId = null;
- observer && observer.disconnect();
- adUnits && adUnits.forEach((unit) => {
- const intersection = intersectionMap[unit.code];
- if (intersection && unit.bids) {
- unit.bids.forEach(bid => {
- bid.intersection = intersection;
- });
- }
- });
- onDone();
- }
-}
-function init(moduleConfig) {
- if (!isFn(window.IntersectionObserver)) {
- logError('IntersectionObserver is not defined');
- observerAvailable = false;
- } else {
- observerAvailable = true;
- }
- return observerAvailable;
-}
-function cloneRect(rect) {
- return rect ? {
- 'left': rect.left,
- 'top': rect.top,
- 'right': rect.right,
- 'bottom': rect.bottom,
- 'width': rect.width,
- 'height': rect.height,
- 'x': rect.x,
- 'y': rect.y,
- } : rect;
-}
-export const intersectionSubmodule = {
- name: 'intersection',
- getBidRequestData: getIntersectionData,
- init: init,
-};
-function registerSubModule() {
- submodule('realTimeData', intersectionSubmodule);
-}
-registerSubModule();
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 18413ad5d77..b2da2f3c077 100644
--- a/modules/ixBidAdapter.js
+++ b/modules/ixBidAdapter.js
@@ -23,14 +23,16 @@ import { registerBidder } from '../src/adapters/bidderFactory.js';
import { INSTREAM, OUTSTREAM } from '../src/video.js';
import { Renderer } from '../src/Renderer.js';
import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const divIdCache = {};
-export function getDivIdFromAdUnitCode(adUnitCode) {
+export function getDivIdFromAdUnit(adUnitCode, target) {
if (divIdCache[adUnitCode]) {
return divIdCache[adUnitCode];
}
- const divId = document.getElementById(adUnitCode) ? adUnitCode : getGptSlotInfoForAdUnitCode(adUnitCode).divId;
+ const element = getAdUnitElement(target);
+ const divId = element?.id ? element.id : getGptSlotInfoForAdUnitCode(adUnitCode).divId;
divIdCache[adUnitCode] = divId;
return divId;
}
@@ -686,8 +688,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 +955,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));
@@ -1006,7 +1005,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;
@@ -1014,12 +1013,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]) {
@@ -1273,10 +1266,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);
@@ -1293,7 +1285,6 @@ function buildIXDiag(validBidRequests, fledgeEnabled) {
version: '$prebid.version$',
url: window.location.href.split('?')[0],
vpd: defaultVideoPlacement,
- ae: fledgeEnabled,
eidLength: allEids.length
};
@@ -1369,7 +1360,7 @@ function createNativeImps(validBidRequest, nativeImps) {
nativeImps[validBidRequest.adUnitCode].tagId = deepAccess(validBidRequest, 'params.tagId');
const adUnitCode = validBidRequest.adUnitCode;
- const divId = getDivIdFromAdUnitCode(adUnitCode);
+ const divId = getDivIdFromAdUnit(adUnitCode, validBidRequest);
nativeImps[validBidRequest.adUnitCode].adUnitCode = adUnitCode;
nativeImps[validBidRequest.adUnitCode].divId = divId;
}
@@ -1391,7 +1382,7 @@ function createVideoImps(validBidRequest, videoImps) {
videoImps[validBidRequest.adUnitCode].tagId = deepAccess(validBidRequest, 'params.tagId');
const adUnitCode = validBidRequest.adUnitCode;
- const divId = getDivIdFromAdUnitCode(adUnitCode);
+ const divId = getDivIdFromAdUnit(adUnitCode, validBidRequest);
videoImps[validBidRequest.adUnitCode].adUnitCode = adUnitCode;
videoImps[validBidRequest.adUnitCode].divId = divId;
}
@@ -1418,23 +1409,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) {
@@ -1447,7 +1421,7 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps, bidde
}
const adUnitCode = validBidRequest.adUnitCode;
- const divId = getDivIdFromAdUnitCode(adUnitCode);
+ const divId = getDivIdFromAdUnit(adUnitCode, validBidRequest);
bannerImps[validBidRequest.adUnitCode].adUnitCode = adUnitCode;
bannerImps[validBidRequest.adUnitCode].divId = divId;
@@ -1515,7 +1489,7 @@ function createMissingBannerImp(bid, imp, newSize) {
function outstreamRenderer(bid) {
bid.renderer.push(function () {
const adUnitCode = bid.adUnitCode;
- const divId = getDivIdFromAdUnitCode(adUnitCode);
+ const divId = getDivIdFromAdUnit(adUnitCode, bid);
if (!divId) {
logWarn(`IX Bid Adapter: adUnitCode: ${divId} not found on page.`);
return;
@@ -1767,9 +1741,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')) {
@@ -1813,29 +1784,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;
},
/**
@@ -2045,15 +1994,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 418fbeb7a63..67895347e73 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 8a6b2909f60..3ff51fce8c1 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 cba29908229..33355868d19 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..8c9eaeb925c 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/livewrappedAnalyticsAdapter.js b/modules/livewrappedAnalyticsAdapter.js
index abeb2095ff7..686d90b7cc7 100644
--- a/modules/livewrappedAnalyticsAdapter.js
+++ b/modules/livewrappedAnalyticsAdapter.js
@@ -4,6 +4,7 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
import { EVENTS } from '../src/constants.js';
import adapterManager from '../src/adapterManager.js';
import { getGlobal } from '../src/prebidGlobal.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const ANALYTICSTYPE = 'endpoint';
const URL = 'https://lwadm.com/analytics/10';
@@ -41,7 +42,7 @@ const livewrappedAnalyticsAdapter = Object.assign(adapter({ EMPTYURL, ANALYTICST
cache.auctions[args.auctionId].gdprApplies = args.gdprConsent ? args.gdprConsent.gdprApplies : undefined;
cache.auctions[args.auctionId].gdprConsent = args.gdprConsent ? args.gdprConsent.consentString : undefined;
let lwFloor;
- const container = document.getElementById(bidRequest.adUnitCode);
+ const container = getAdUnitElement(bidRequest);
let adUnitId = container ? container.getAttribute('data-adunitid') : undefined;
adUnitId = adUnitId != null ? adUnitId : undefined;
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 18aac8faa0d..aeff148880f 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 78016f9fa56..52f7718a7ab 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 633f5c380ff..074a96b6268 100644
--- a/modules/marsmediaBidAdapter.js
+++ b/modules/marsmediaBidAdapter.js
@@ -1,11 +1,12 @@
'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 { getAdUnitElement } from '../src/utils/adUnits.js';
+import { getDNT } from '../libraries/dnt/index.js';
function MarsmediaAdapter() {
this.code = 'marsmedia';
@@ -167,7 +168,7 @@ function MarsmediaAdapter() {
bidSizes = bidSizes.filter(size => isArray(size));
const processedSizes = bidSizes.map(size => ({ w: parseInt(size[0], 10), h: parseInt(size[1], 10) }));
- const element = document.getElementById(bid.adUnitCode);
+ const element = getAdUnitElement(bid);
const minSize = getMinSize(processedSizes);
const viewabilityAmount = _isViewabilityMeasurable(element)
? _getViewability(element, getWindowTop(), minSize)
diff --git a/modules/mediaforceBidAdapter.js b/modules/mediaforceBidAdapter.js
index fa728d01944..2fda15971ea 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 135ee52a880..7fe6538c7ad 100644
--- a/modules/mediafuseBidAdapter.js
+++ b/modules/mediafuseBidAdapter.js
@@ -28,6 +28,8 @@ import {
} from '../libraries/appnexusUtils/anKeywords.js';
import { convertCamelToUnderscore } from '../libraries/appnexusUtils/anUtils.js';
import { chunk } from '../libraries/chunk/chunk.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
+
const BIDDER_CODE = 'mediafuse';
const GVLID = 32;
const ENDPOINT_URL_NORMAL = 'https://ib.adnxs.com/openrtb2/prebidjs';
@@ -491,7 +493,7 @@ const converter = ortbConverter({
tag_id: extANData.tag_id,
uuid: bidResponse.requestId
};
- bidResponse.renderer = newRenderer(bidRequest.adUnitCode, {
+ bidResponse.renderer = newRenderer(bidRequest, {
renderer_url: extANData.renderer_url,
renderer_id: extANData.renderer_id,
}, rendererOptions);
@@ -676,13 +678,13 @@ function getBidFloor(bid) {
return null;
}
-function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) {
+function newRenderer(bidRequest, rtbBid, rendererOptions = {}) {
const renderer = Renderer.install({
id: rtbBid.renderer_id,
url: rtbBid.renderer_url,
config: rendererOptions,
loaded: false,
- adUnitCode,
+ adUnitCode: bidRequest.adUnitCode,
});
try {
@@ -696,7 +698,7 @@ function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) {
loaded: () => logMessage('Mediafuse outstream video loaded event'),
ended: () => {
logMessage('Mediafuse outstream renderer video event');
- const el = document.getElementById(adUnitCode);
+ const el = getAdUnitElement(bidRequest);
if (el) {
el.style.display = 'none';
}
@@ -705,9 +707,9 @@ function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) {
return renderer;
}
-function hidedfpContainer(elementId) {
+function hidedfpContainer(container) {
try {
- const el = document.getElementById(elementId).querySelectorAll("div[id^='google_ads']");
+ const el = container.querySelectorAll("div[id^='google_ads']");
if (el[0]) {
el[0].style.setProperty('display', 'none');
}
@@ -716,9 +718,9 @@ function hidedfpContainer(elementId) {
}
}
-function hideSASIframe(elementId) {
+function hideSASIframe(container) {
try {
- const el = document.getElementById(elementId).querySelectorAll("script[id^='sas_script']");
+ const el = container.querySelectorAll("script[id^='sas_script']");
if (el[0]?.nextSibling?.localName === 'iframe') {
el[0].nextSibling.style.setProperty('display', 'none');
}
@@ -739,8 +741,9 @@ function handleOutstreamRendererEvents(bid, id, eventName) {
}
function outstreamRender(bid, doc) {
- hidedfpContainer(bid.adUnitCode);
- hideSASIframe(bid.adUnitCode);
+ const container = getAdUnitElement(bid);
+ hidedfpContainer(container);
+ hideSASIframe(container);
bid.renderer.push(() => {
const win = doc?.defaultView || window;
if (win.ANOutstreamVideo) {
diff --git a/modules/mediakeysBidAdapter.js b/modules/mediakeysBidAdapter.js
index 4aed102c6dc..c7065a95f2b 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 3a98dcf57b9..f8ff33ddc81 100644
--- a/modules/medianetBidAdapter.js
+++ b/modules/medianetBidAdapter.js
@@ -23,6 +23,7 @@ import { GLOBAL_VENDOR_ID, MEDIANET } from '../libraries/medianetUtils/constants
import { getGlobal } from '../src/prebidGlobal.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { getMinSize } from '../libraries/sizeUtils/sizeUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -133,11 +134,11 @@ function getWindowSize() {
}
}
-function getCoordinates(adUnitCode) {
- let element = document.getElementById(adUnitCode);
- if (!element && adUnitCode.indexOf('/') !== -1) {
+function getCoordinates(bidRequest) {
+ let element = getAdUnitElement(bidRequest);
+ if (!element && bidRequest.adUnitCode.indexOf('/') !== -1) {
// now it means that adUnitCode is GAM AdUnitPath
- const { divId } = getGptSlotInfoForAdUnitCode(adUnitCode);
+ const { divId } = getGptSlotInfoForAdUnitCode(bidRequest.adUnitCode);
if (isStr(divId)) {
element = document.getElementById(divId);
}
@@ -239,7 +240,7 @@ function slotParams(bidRequest, bidderRequests) {
if (bidFloor) {
params.bidfloor = bidFloor;
}
- const coordinates = getCoordinates(bidRequest.adUnitCode);
+ const coordinates = getCoordinates(bidRequest);
if (coordinates && params.banner && params.banner.length !== 0) {
const normCoordinates = normalizeCoordinates(coordinates);
params.ext.coordinates = normCoordinates;
@@ -256,9 +257,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 +485,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 +500,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 367f9046184..f370d220464 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 7fb1def9a19..28728615051 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/msftBidAdapter.js b/modules/msftBidAdapter.js
index 8cc396a9417..e9539cce6fc 100644
--- a/modules/msftBidAdapter.js
+++ b/modules/msftBidAdapter.js
@@ -31,6 +31,7 @@ import {
logWarn,
mergeDeep
} from "../src/utils.js";
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = "msft";
const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout'];
@@ -502,12 +503,10 @@ function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) {
/**
* This function hides google div container for outstream bids to remove unwanted space on page. Appnexus renderer creates a new iframe outside of google iframe to render the outstream creative.
- * @param {string} elementId element id
*/
-function hidedfpContainer(elementId) {
+function hidedfpContainer(container) {
try {
- const el = document
- .getElementById(elementId)
+ const el = container
.querySelectorAll("div[id^='google_ads']");
if (el[0]) {
el[0].style.setProperty("display", "none");
@@ -517,11 +516,10 @@ function hidedfpContainer(elementId) {
}
}
-function hideSASIframe(elementId) {
+function hideSASIframe(container) {
try {
// find script tag with id 'sas_script'. This ensures it only works if you're using Smart Ad Server.
- const el = document
- .getElementById(elementId)
+ const el = container
.querySelectorAll("script[id^='sas_script']");
if (el[0]?.nextSibling?.localName === "iframe") {
el[0].nextSibling.style.setProperty("display", "none");
@@ -539,8 +537,9 @@ function handleOutstreamRendererEvents(bid, id, eventName) {
}
function outstreamRender(bid, doc) {
- hidedfpContainer(bid.adUnitCode);
- hideSASIframe(bid.adUnitCode);
+ const container = getAdUnitElement(bid);
+ hidedfpContainer(container);
+ hideSASIframe(container);
// push to render queue because ANOutstreamVideo may not be loaded yet
bid.renderer.push(() => {
const win = doc?.defaultView || window;
diff --git a/modules/nexverseBidAdapter.js b/modules/nexverseBidAdapter.js
index a52bc9ffa4c..4e65a98066c 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,8 @@ 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 { getAdUnitElement } from '../src/utils/adUnits.js';
+import { getDNT } from '../libraries/dnt/index.js';
const BIDDER_CODE = 'nexverse';
const BIDDER_ENDPOINT = 'https://rtb.nexverse.ai';
@@ -191,7 +192,7 @@ function buildOpenRtbRequest(bid, bidderRequest) {
const imps = [];
// Calculate viewability percentage for the ad unit
- const adUnitElement = document.getElementById(bid.adUnitCode);
+ const adUnitElement = getAdUnitElement(bid);
let viewabilityPercentage = 0;
if (adUnitElement) {
const rect = getBoundingClientRect(adUnitElement);
diff --git a/modules/omsBidAdapter.js b/modules/omsBidAdapter.js
index 99efb9198e5..d9f1e8091db 100644
--- a/modules/omsBidAdapter.js
+++ b/modules/omsBidAdapter.js
@@ -1,7 +1,10 @@
import {
+ isArray,
+ getWindowTop,
deepSetValue,
logError,
logWarn,
+ createTrackPixelHtml,
getBidIdParameter,
getUniqueIdentifierStr,
formatQS,
@@ -10,9 +13,11 @@ import {
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { ajax } from '../src/ajax.js';
+import { percentInView } from '../libraries/percentInView/percentInView.js';
import { getUserSyncParams } from '../libraries/userSyncUtils/userSyncUtils.js';
-import { getAdMarkup, getBidFloor, getDeviceType, getProcessedSizes } from '../libraries/omsUtils/index.js';
-import { getRoundedViewability } from '../libraries/omsUtils/viewability.js';
+import { getMinSize } from '../libraries/sizeUtils/sizeUtils.js';
+import { getBidFloor, isIframe } from '../libraries/omsUtils/index.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'oms';
const URL = 'https://rt.marphezis.com/hb';
@@ -35,9 +40,15 @@ export const spec = {
function buildRequests(bidReqs, bidderRequest) {
try {
const impressions = bidReqs.map(bid => {
- const bidSizes = bid?.mediaTypes?.banner?.sizes || bid.sizes || [];
- const processedSizes = getProcessedSizes(bidSizes);
- const viewabilityAmountRounded = getRoundedViewability(bid.adUnitCode, processedSizes);
+ let bidSizes = bid?.mediaTypes?.banner?.sizes || bid.sizes || [];
+ bidSizes = ((isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes]);
+ bidSizes = bidSizes.filter(size => isArray(size));
+ const processedSizes = bidSizes.map(size => ({ w: parseInt(size[0], 10), h: parseInt(size[1], 10) }));
+
+ const element = getAdUnitElement(bid);
+ const minSize = getMinSize(processedSizes);
+ const viewabilityAmount = _isViewabilityMeasurable(element) ? _getViewability(element, getWindowTop(), minSize) : 'na';
+ const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount);
const gpidData = _extractGpidData(bid);
const imp = {
@@ -91,7 +102,7 @@ function buildRequests(bidReqs, bidderRequest) {
}
},
device: {
- devicetype: getDeviceType(navigator.userAgent, bidderRequest?.ortb2?.device?.sua),
+ devicetype: _getDeviceType(navigator.userAgent, bidderRequest?.ortb2?.device?.sua),
w: screen.width,
h: screen.height
},
@@ -182,7 +193,7 @@ function interpretResponse(serverResponse) {
bidResponse.vastXml = bid.adm;
} else {
bidResponse.mediaType = BANNER;
- bidResponse.ad = getAdMarkup(bid);
+ bidResponse.ad = _getAdMarkup(bid);
}
return bidResponse;
@@ -234,6 +245,18 @@ function _trackEvent(endpoint, data) {
});
}
+function _getDeviceType(ua, sua) {
+ if (sua?.mobile || (/(ios|ipod|ipad|iphone|android)/i).test(ua)) {
+ return 1
+ }
+
+ if ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(ua)) {
+ return 3
+ }
+
+ return 2
+}
+
function _getGpp(bidderRequest) {
if (bidderRequest?.gppConsent != null) {
return bidderRequest.gppConsent;
@@ -244,6 +267,22 @@ function _getGpp(bidderRequest) {
);
}
+function _getAdMarkup(bid) {
+ let adm = bid.adm;
+ if ('nurl' in bid) {
+ adm += createTrackPixelHtml(bid.nurl);
+ }
+ return adm;
+}
+
+function _isViewabilityMeasurable(element) {
+ return !isIframe() && element !== null;
+}
+
+function _getViewability(element, topWin, { w, h } = {}) {
+ return getWindowTop().document.visibilityState === 'visible' ? percentInView(element, { w, h }) : 0;
+}
+
function _extractGpidData(bid) {
return {
gpid: bid?.ortb2Imp?.ext?.gpid,
diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js
index d919d1398b7..3d70c233805 100644
--- a/modules/onetagBidAdapter.js
+++ b/modules/onetagBidAdapter.js
@@ -9,6 +9,7 @@ import { deepClone, logError, deepAccess, getWinDimensions } from '../src/utils.
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { toOrtbNativeRequest } from '../src/native.js';
import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -145,7 +146,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 +161,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 +207,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 = {}) {
@@ -366,14 +359,14 @@ function setGeneralInfo(bidRequest) {
if (params.dealId) {
this['dealId'] = params.dealId;
}
- const coords = getSpaceCoords(bidRequest.adUnitCode);
+ const coords = getSpaceCoords(bidRequest);
if (coords) {
this['coords'] = coords;
}
}
-function getSpaceCoords(id) {
- const space = document.getElementById(id);
+function getSpaceCoords(bidRequest) {
+ const space = getAdUnitElement(bidRequest);
try {
const { top, left, width, height } = getBoundingClientRect(space);
let window = space.ownerDocument.defaultView;
diff --git a/modules/onomagicBidAdapter.js b/modules/onomagicBidAdapter.js
index ef4d3df777e..1dade3668ea 100644
--- a/modules/onomagicBidAdapter.js
+++ b/modules/onomagicBidAdapter.js
@@ -1,14 +1,18 @@
import {
_each,
- getBidIdParameter,
+ createTrackPixelHtml, getBidIdParameter,
getUniqueIdentifierStr,
+ getWindowTop,
+ isArray,
logError,
logWarn
} from '../src/utils.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
-import { getAdMarkup, getBidFloor, getDeviceType, getProcessedSizes } from '../libraries/omsUtils/index.js';
-import { getRoundedViewability } from '../libraries/omsUtils/viewability.js';
+import { percentInView } from '../libraries/percentInView/percentInView.js';
+import { getMinSize } from '../libraries/sizeUtils/sizeUtils.js';
+import { getBidFloor, isIframe } from '../libraries/omsUtils/index.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'onomagic';
const URL = 'https://bidder.onomagic.com/hb';
@@ -31,9 +35,17 @@ function buildRequests(bidReqs, bidderRequest) {
const onomagicImps = [];
const publisherId = getBidIdParameter('publisherId', bidReqs[0].params);
_each(bidReqs, function (bid) {
- const bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes;
- const processedSizes = getProcessedSizes(bidSizes);
- const viewabilityAmountRounded = getRoundedViewability(bid.adUnitCode, processedSizes);
+ let bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes;
+ bidSizes = ((isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes]);
+ bidSizes = bidSizes.filter(size => isArray(size));
+ const processedSizes = bidSizes.map(size => ({ w: parseInt(size[0], 10), h: parseInt(size[1], 10) }));
+
+ const element = getAdUnitElement(bid);
+ const minSize = getMinSize(processedSizes);
+ const viewabilityAmount = _isViewabilityMeasurable(element)
+ ? _getViewability(element, getWindowTop(), minSize)
+ : 'na';
+ const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount);
const imp = {
id: bid.bidId,
@@ -63,7 +75,7 @@ function buildRequests(bidReqs, bidderRequest) {
}
},
device: {
- devicetype: getDeviceType(),
+ devicetype: _getDeviceType(),
w: screen.width,
h: screen.height
},
@@ -116,7 +128,7 @@ function interpretResponse(serverResponse) {
currency: 'USD',
netRevenue: true,
mediaType: BANNER,
- ad: getAdMarkup(onomagicBid),
+ ad: _getAdMarkup(onomagicBid),
ttl: 60,
meta: {
advertiserDomains: onomagicBid && onomagicBid.adomain ? onomagicBid.adomain : []
@@ -135,4 +147,34 @@ function getUserSyncs(syncOptions, responses, gdprConsent) {
return [];
}
+function _isMobile() {
+ return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent);
+}
+
+function _isConnectedTV() {
+ return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent);
+}
+
+function _getDeviceType() {
+ return _isMobile() ? 1 : _isConnectedTV() ? 3 : 2;
+}
+
+function _getAdMarkup(bid) {
+ let adm = bid.adm;
+ if ('nurl' in bid) {
+ adm += createTrackPixelHtml(bid.nurl);
+ }
+ return adm;
+}
+
+function _isViewabilityMeasurable(element) {
+ return !isIframe() && element !== null;
+}
+
+function _getViewability(element, topWin, { w, h } = {}) {
+ return getWindowTop().document.visibilityState === 'visible'
+ ? percentInView(element, { w, h })
+ : 0;
+}
+
registerBidder(spec);
diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js
index 2e295cc8669..9627223b221 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 33a86fc7330..4a8e22aaa6a 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 1d7aff59ee2..ee631309610 100644
--- a/modules/ozoneBidAdapter.js
+++ b/modules/ozoneBidAdapter.js
@@ -1,13 +1,15 @@
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';
@@ -16,6 +18,7 @@ import { getPriceBucketString } from '../src/cpmBucketManager.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 e7e00b3f4e8..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 a7f1dc609f4..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..5de64af33ff 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 9f875321934..056eca786a1 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 0ced549fca6..47edd70eed2 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 511f0b8eca5..4a1161fca73 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';
@@ -9,6 +9,7 @@ import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { NATIVE_ASSET_TYPES, NATIVE_IMAGE_TYPES, PREBID_NATIVE_DATA_KEYS_TO_ORTB, NATIVE_KEYS_THAT_ARE_NOT_ASSETS, NATIVE_KEYS } from '../src/constants.js';
import { addDealCustomTargetings, addPMPDeals } from '../libraries/dealUtils/dealUtils.js';
import { getConnectionType } from '../libraries/connectionInfo/connectionUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -95,7 +96,7 @@ const converter = ortbConverter({
if (imp.hasOwnProperty('banner')) updateBannerImp(imp.banner, adSlot);
if (imp.hasOwnProperty('video')) updateVideoImp(mediaTypes?.video, adUnitCode, imp);
if (imp.hasOwnProperty('native')) updateNativeImp(imp, mediaTypes?.native);
- if (imp.hasOwnProperty('banner') || imp.hasOwnProperty('video')) addViewabilityToImp(imp, adUnitCode, bidRequest?.sizes);
+ if (imp.hasOwnProperty('banner') || imp.hasOwnProperty('video')) addViewabilityToImp(imp, bidRequest, bidRequest?.sizes);
if (pmzoneid) imp.ext.pmZoneId = pmzoneid;
setImpTagId(imp, adSlot.trim(), hashedKey);
setImpFields(imp);
@@ -142,12 +143,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 {
@@ -529,27 +529,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
@@ -626,7 +605,7 @@ const BB_RENDERER = {
}
const rendererId = BB_RENDERER.getRendererId(PUBLICATION, bid.rendererCode);
- const ele = document.getElementById(bid.adUnitCode); // NB convention
+ const ele = getAdUnitElement(bid);
const renderer = window.bluebillywig.renderers.find(r => r._id === rendererId);
if (renderer) renderer.bootstrap(config, ele);
@@ -728,10 +707,10 @@ function _getMinSize(sizes) {
/**
* Measures viewability for an element and adds it to the imp object at the ext level
* @param {Object} imp - The impression object
- * @param {string} adUnitCode - The ad unit code for element identification
+ * @param {Object} bidRequest - The bid request for element identification
* @param {Object} sizes - Sizes object with width and height properties
*/
-export const addViewabilityToImp = (imp, adUnitCode, sizes) => {
+export const addViewabilityToImp = (imp, bidRequest, sizes) => {
let elementSize = { w: 0, h: 0 };
if (imp.video?.w > 0 && imp.video?.h > 0) {
@@ -740,7 +719,7 @@ export const addViewabilityToImp = (imp, adUnitCode, sizes) => {
} else {
elementSize = _getMinSize(sizes);
}
- const element = document.getElementById(adUnitCode);
+ const element = getAdUnitElement(bidRequest);
if (!element) return;
const viewabilityAmount = isViewabilityMeasurable(element)
diff --git a/modules/pwbidBidAdapter.js b/modules/pwbidBidAdapter.js
index eaa06107b39..1d2fa182b79 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 e8dc9ff6852..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 4b4d7b97d40..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 ca268a6f949..f7518d0d916 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 fa91f22b467..8a358aead21 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 60276400c1d..0fde369867d 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 fcea9317881..71613297001 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/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js
index 10b1a872fed..c38325ece0a 100644
--- a/modules/seedtagBidAdapter.js
+++ b/modules/seedtagBidAdapter.js
@@ -5,6 +5,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { _map, getWinDimensions, isArray, triggerPixel } from '../src/utils.js';
import { getViewportCoordinates } from '../libraries/viewport/viewport.js';
import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -121,7 +122,7 @@ function buildBidRequest(validBidRequest) {
supplyTypes: mediaTypes,
adUnitId: params.adUnitId,
adUnitCode: validBidRequest.adUnitCode,
- geom: geom(validBidRequest.adUnitCode),
+ geom: geom(validBidRequest),
placement: params.placement,
requestCount: validBidRequest.bidderRequestsCount || 1,
};
@@ -215,8 +216,8 @@ function ttfb() {
return ttfb >= 0 && ttfb <= performance.now() ? ttfb : 0;
}
-function geom(adunitCode) {
- const slot = document.getElementById(adunitCode);
+function geom(bidRequest) {
+ const slot = getAdUnitElement(bidRequest);
if (slot) {
const { top, left, width, height } = getBoundingClientRect(slot);
const viewport = {
diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js
index a11820b5897..406ed77fc2b 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 1ee5888c67f..c579619c8db 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 28fbdf61ae7..99bb13ff3a7 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');
@@ -148,39 +130,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;
});
@@ -248,15 +216,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;
@@ -276,15 +235,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 = {
@@ -292,7 +245,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);
}
@@ -363,7 +316,6 @@ const converter = ortbConverter({
imp: {
banner(orig, imp, bidRequest, context) {
const mediaType = context.mediaType;
-
if (mediaType === BANNER) {
imp.bidfloor = getBidFloor(bidRequest, BANNER, getAdUnitSizes(bidRequest));
}
@@ -376,11 +328,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);
@@ -388,7 +338,6 @@ const converter = ortbConverter({
native(orig, imp, bidRequest, context) {
const mediaType = context.mediaType;
-
if (mediaType === NATIVE) {
imp.bidfloor = getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(bidRequest.nativeOrtbRequest));
}
@@ -432,81 +381,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 a012f2ca2f4..46765cf217c 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 15d09b2fa26..44fa0e257c7 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/sparteoBidAdapter.js b/modules/sparteoBidAdapter.js
index 9332e99a6f5..f7a6c472815 100644
--- a/modules/sparteoBidAdapter.js
+++ b/modules/sparteoBidAdapter.js
@@ -91,6 +91,7 @@ function createRenderer(rendererConfig) {
}
function outstreamRender(bid) {
+ // TODO this should use getAdUnitElement
if (!document.getElementById(bid.adUnitCode)) {
logError(`Sparteo Bid Adapter: Video renderer did not started. bidResponse.adUnitCode is probably not a DOM element : ${bid.adUnitCode}`);
return;
diff --git a/modules/sspBCBidAdapter.js b/modules/sspBCBidAdapter.js
index 7a7275d5ff2..72caeb713e4 100644
--- a/modules/sspBCBidAdapter.js
+++ b/modules/sspBCBidAdapter.js
@@ -6,6 +6,7 @@ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js';
+import { EVENT_TYPE_VIEWABLE, TRACKER_METHOD_IMG } from '../src/eventTrackers.js';
const BIDDER_CODE = 'sspBC';
const BIDDER_URL = 'https://ssp.wp.pl/bidder/';
@@ -671,8 +672,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)
@@ -738,6 +738,7 @@ const spec = {
},
netRevenue: true,
vurls,
+ eventtrackers: vurls.map(url => ({ event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url })),
};
// mediaType and ad data for instream / native / banner
@@ -788,7 +789,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 188ece48107..9ee860883d2 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/stroeerCoreBidAdapter.js b/modules/stroeerCoreBidAdapter.js
index f04080709a0..3a73cbbac6b 100644
--- a/modules/stroeerCoreBidAdapter.js
+++ b/modules/stroeerCoreBidAdapter.js
@@ -156,6 +156,7 @@ const isMainPageAccessible = () => {
}
const elementInView = (elementId) => {
+ // TODO this should use getAdUnitElement
const resolveElement = (elId) => {
const win = getWindowSelf();
diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js
index a82cdf0adf0..b4b04d4123a 100644
--- a/modules/taboolaBidAdapter.js
+++ b/modules/taboolaBidAdapter.js
@@ -3,7 +3,14 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, NATIVE } 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,
+ safeJSONParse
+} from '../src/utils.js';
import { getStorageManager } from '../src/storageManager.js';
import { ajax } from '../src/ajax.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
@@ -11,6 +18,7 @@ import { getConnectionType } from '../libraries/connectionInfo/connectionUtils.j
import { getViewportCoordinates } from '../libraries/viewport/viewport.js';
import { percentInView } from '../libraries/percentInView/percentInView.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'taboola';
const GVLID = 42;
@@ -140,9 +148,9 @@ export function getDeviceExtSignals(existingExt = {}) {
};
}
-export function getElementSignals(adUnitCode) {
+export function getElementSignals(bidRequest) {
try {
- const element = document.getElementById(adUnitCode);
+ const element = getAdUnitElement(bidRequest);
if (!element) return null;
const rect = getBoundingClientRect(element);
@@ -247,58 +255,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) => {
@@ -501,7 +462,7 @@ function fillTaboolaImpData(bid, imp, context) {
deepSetValue(imp, 'ext.prebid.bidderRequestsCount', bid.bidderRequestsCount);
deepSetValue(imp, 'ext.prebid.bidderWinsCount', bid.bidderWinsCount);
- const elementSignals = getElementSignals(bid.adUnitCode);
+ const elementSignals = getElementSignals(bid);
if (elementSignals) {
if (elementSignals.viewability !== undefined) {
deepSetValue(imp, 'ext.viewability', elementSignals.viewability);
diff --git a/modules/tappxBidAdapter.js b/modules/tappxBidAdapter.js
index 869222a6614..266a0186e30 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 168990f84c0..4e140cb0913 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 2d4343b329e..bac8645eb0b 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 60eb99f8588..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 4cbe600df92..a9284e08400 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 1da498cbe06..944c75ae616 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 5b791bf6a25..1794de9ed0d 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/underdogmediaBidAdapter.js b/modules/underdogmediaBidAdapter.js
index 738fb22e312..d78782ad3f1 100644
--- a/modules/underdogmediaBidAdapter.js
+++ b/modules/underdogmediaBidAdapter.js
@@ -13,6 +13,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js';
import { isSlotMatchingAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
import { percentInView } from '../libraries/percentInView/percentInView.js';
import { isIframe } from '../libraries/omsUtils/index.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'underdogmedia';
const UDM_ADAPTER_VERSION = '7.30V';
@@ -109,7 +110,7 @@ export const spec = {
sizes = flatten(sizes, parseSizesInput(bidParamSizes));
siteId = +bidParam.params.siteId;
const adUnitCode = bidParam.adUnitCode
- const element = _getAdSlotHTMLElement(adUnitCode)
+ const element = _getAdSlotHTMLElement(bidParam)
const minSize = _getMinSize(bidParamSizes)
placementObject.sizes = parseSizesInput(bidParamSizes)
@@ -234,9 +235,9 @@ function _getMinSize(bidParamSizes) {
return bidParamSizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min)
}
-function _getAdSlotHTMLElement(adUnitCode) {
- return document.getElementById(adUnitCode) ||
- document.getElementById(_mapAdUnitPathToElementId(adUnitCode));
+function _getAdSlotHTMLElement(bidRequest) {
+ return getAdUnitElement(bidRequest) ||
+ document.getElementById(_mapAdUnitPathToElementId(bidRequest.adUnitCode));
}
function _mapAdUnitPathToElementId(adUnitCode) {
diff --git a/modules/undertoneBidAdapter.js b/modules/undertoneBidAdapter.js
index fbfd236e91f..e1da10b1da0 100644
--- a/modules/undertoneBidAdapter.js
+++ b/modules/undertoneBidAdapter.js
@@ -7,6 +7,7 @@ import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingC
import { getViewportCoordinates } from '../libraries/viewport/viewport.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'undertone';
const URL = 'https://hb.undertone.com/hb';
@@ -38,8 +39,8 @@ function getGdprQueryParams(gdprConsent) {
return `gdpr=${gdpr}&gdprstr=${gdprstr}`;
}
-function getBannerCoords(id) {
- const element = document.getElementById(id);
+function getBannerCoords(bidRequest) {
+ const element = getAdUnitElement(bidRequest);
if (element) {
const { left, top } = getBoundingClientRect(element);
const viewport = getViewportCoordinates();
@@ -109,7 +110,7 @@ export const spec = {
validBidRequests.forEach(bidReq => {
const bid = {
bidRequestId: bidReq.bidId,
- coordinates: getBannerCoords(bidReq.adUnitCode),
+ coordinates: getBannerCoords(bidReq),
hbadaptor: 'prebid',
url: pageUrl,
domain: domain,
diff --git a/modules/userId/userId.md b/modules/userId/userId.md
index f7bea8fd9f8..328e23d96b0 100644
--- a/modules/userId/userId.md
+++ b/modules/userId/userId.md
@@ -26,16 +26,6 @@ pbjs.setConfig({
name: "_pubcid",
expires: 60
}
- }, {
- name: 'dmdId',
- storage: {
- name: 'dmd-dgid',
- type: 'cookie',
- expires: 30
- },
- params: {
- api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c', // provided by DMD
- }
}, {
name: "unifiedId",
params: {
diff --git a/modules/valuadBidAdapter.js b/modules/valuadBidAdapter.js
index ec969ab719d..31b320c2557 100644
--- a/modules/valuadBidAdapter.js
+++ b/modules/valuadBidAdapter.js
@@ -12,6 +12,7 @@ import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
import { config } from '../src/config.js';
import { getBoundingBox, percentInView } from '../libraries/percentInView/percentInView.js';
import { isIframe } from '../libraries/omsUtils/index.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'valuad';
const GVL_ID = 1478;
@@ -106,7 +107,7 @@ const converter = ortbConverter({
const size = { w: adSize[0], h: adSize[1] };
- const element = document.getElementById(bid.adUnitCode) || document.getElementById(getGptSlotInfoForAdUnitCode(bid.adUnitCode)?.divId);
+ const element = getAdUnitElement(bid) || document.getElementById(getGptSlotInfoForAdUnitCode(bid.adUnitCode)?.divId);
const viewabilityAmount = _isViewabilityMeasurable(element) ? _getViewability(element, getWindowTop(), size) : 0;
const rect = element && getBoundingBox(element, size);
diff --git a/modules/visxBidAdapter.js b/modules/visxBidAdapter.js
index f75fc1fe4ef..bc7f72833f3 100644
--- a/modules/visxBidAdapter.js
+++ b/modules/visxBidAdapter.js
@@ -7,6 +7,7 @@ import { getStorageManager } from '../src/storageManager.js';
import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
import { getBidFromResponse } from '../libraries/processResponse/index.js';
import { getCurrencyFromBidderRequest } from '../libraries/ortb2Utils/currency.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'visx';
const GVLID = 154;
@@ -295,7 +296,7 @@ function makeVideo(videoParams = {}) {
}
function buildImpObject(bid) {
- const { params: { uid }, bidId, mediaTypes, sizes, adUnitCode } = bid;
+ const { params: { uid }, bidId, mediaTypes, sizes } = bid;
const video = mediaTypes && _isVideoBid(bid) && _isValidVideoBid(bid) && makeVideo(mediaTypes.video);
const banner = makeBanner((mediaTypes && mediaTypes.banner) || (!video && { sizes }));
const impObject = {
@@ -308,7 +309,7 @@ function buildImpObject(bid) {
};
if (impObject.banner) {
- impObject.ext.bidder.adslotExists = _isAdSlotExists(adUnitCode);
+ impObject.ext.bidder.adslotExists = _isAdSlotExists(bid);
}
if (bid.ortb2Imp?.ext?.gpid) {
@@ -410,12 +411,12 @@ function _isValidVideoBid(bid, logErrors = false) {
return result;
}
-function _isAdSlotExists(adUnitCode) {
- if (document.getElementById(adUnitCode)) {
+function _isAdSlotExists(bidRequest) {
+ if (getAdUnitElement(bidRequest)) {
return true;
}
- const gptAdSlot = getGptSlotInfoForAdUnitCode(adUnitCode);
+ const gptAdSlot = getGptSlotInfoForAdUnitCode(bidRequest.adUnitCode);
if (gptAdSlot.divId && document.getElementById(gptAdSlot.divId)) {
return true;
}
diff --git a/modules/widespaceBidAdapter.js b/modules/widespaceBidAdapter.js
index 498cf5ba7ea..51bd244009d 100644
--- a/modules/widespaceBidAdapter.js
+++ b/modules/widespaceBidAdapter.js
@@ -4,6 +4,7 @@ import { deepClone, parseQueryStringParameters, parseSizesInput } from '../src/u
import { getStorageManager } from '../src/storageManager.js';
import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingClientRect.js';
import { getConnectionInfo } from '../libraries/connectionInfo/connectionUtils.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
const BIDDER_CODE = 'widespace';
const WS_ADAPTER_VERSION = '2.0.1';
@@ -53,7 +54,7 @@ export const spec = {
'inFrame': 1,
'sid': bid.params.sid,
'lcuid': LC_UID,
- 'vol': isInHostileIframe ? '' : visibleOnLoad(document.getElementById(bid.adUnitCode)),
+ 'vol': isInHostileIframe ? '' : visibleOnLoad(getAdUnitElement(bid)),
'gdprCmp': bidderRequest && bidderRequest.gdprConsent ? 1 : 0,
'hb': '1',
'hb.cd': CUST_DATA ? encodedParamValue(CUST_DATA) : '',
diff --git a/modules/yandexBidAdapter.js b/modules/yandexBidAdapter.js
index 901bbcf29de..910a8e75a87 100644
--- a/modules/yandexBidAdapter.js
+++ b/modules/yandexBidAdapter.js
@@ -7,6 +7,7 @@ import { getBoundingClientRect } from '../libraries/boundingClientRect/boundingC
import { ajax } from '../src/ajax.js';
import { config as pbjsConfig } from '../src/config.js';
import { isWebdriverEnabled } from '../libraries/webdriver/webdriver.js';
+import { getAdUnitElement } from '../src/utils/adUnits.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
@@ -183,7 +184,7 @@ export const spec = {
queryParams['tcf-consent'] = consentString;
}
- const adUnitElement = document.getElementById(bidRequest.params.pubcontainerid || bidRequest.adUnitCode);
+ const adUnitElement = bidRequest.params.pubcontainerid ? document.getElementById(bidRequest.params.pubcontainerid) : getAdUnitElement(bidRequest);
const windowContext = getContext(adUnitElement);
const isIframe = inIframe();
const coords = isIframe ? getFramePosition() : {
diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js
index eb3ee1de1da..89502f490c3 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/scope3_segtax_pr.md b/scope3_segtax_pr.md
deleted file mode 100644
index 7589507f8a4..00000000000
--- a/scope3_segtax_pr.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Proposed Addition to segtax.md
-
-Add this line to the "Vendor-specific Taxonomies" section (in numerical order):
-
-```
-604: Scope3 Agentic Execution Engine (AEE) Targeting Signals
-```
-
-## PR Description Template:
-
-**Title:** Add Scope3 AEE Targeting Signals Taxonomy (segtax ID 604)
-
-**Description:**
-
-This PR registers Scope3's Agentic Execution Engine (AEE) targeting signal taxonomy for use in OpenRTB segment data.
-
-**Details:**
-- **Taxonomy ID:** 604
-- **Name:** Scope3 Agentic Execution Engine (AEE) Targeting Signals
-- **Purpose:** Identifies proprietary targeting signals generated by Scope3's AEE for real-time programmatic optimization
-- **Usage:** These are opaque targeting codes (e.g., "x82s", "a91k") used for line item targeting decisions, not traditional audience segments
-
-**Contact:** [Your email]
-
-cc: @bretg @slimkrazy (as listed approvers in the document)
-
-## Alternative Higher ID:
-
-If you want to avoid any potential conflicts with IDs in the 600s range, you could use:
-
-```
-1001: Scope3 Agentic Execution Engine (AEE) Targeting Signals
-```
-
-This would put you well clear of any existing entries while still in the vendor-specific range.
\ No newline at end of file
diff --git a/src/adRendering.ts b/src/adRendering.ts
index dc214734dd9..c7b02468f7d 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/adUnits.ts b/src/adUnits.ts
index a1aced172ef..bdc86ee33b5 100644
--- a/src/adUnits.ts
+++ b/src/adUnits.ts
@@ -88,6 +88,11 @@ export interface AdUnitDefinition {
* Used by setTargetingForGPTAsync() to match which auction is for which ad slot.
*/
code: AdUnitCode;
+ /**
+ * A DOM element corresponding to this ad unit.
+ * By default, this is `document.getElementById(adUnit.code)`.
+ */
+ element?: HTMLElement;
/**
* Bid requests representing demand partners and associated parameters.
*/
diff --git a/src/adapterManager.ts b/src/adapterManager.ts
index 81c63be66bc..328ab57335d 100644
--- a/src/adapterManager.ts
+++ b/src/adapterManager.ts
@@ -214,6 +214,7 @@ const ADUNIT_BID_PROPERTIES = [
'nativeParams',
'nativeOrtbRequest',
'renderer',
+ 'element',
] as const;
type GetBidsOptions = {
diff --git a/src/adapters/bidderFactory.ts b/src/adapters/bidderFactory.ts
index 0376e3a0607..737c26117e1 100644
--- a/src/adapters/bidderFactory.ts
+++ b/src/adapters/bidderFactory.ts
@@ -279,11 +279,11 @@ export function newBidder(spec: BidderSpec) {
const tidGuard = guardTids(bidderRequest);
const adUnitCodesHandled = {};
- function addBidWithCode(adUnitCode: string, bid: Bid) {
+ function addBidWithCode(adUnitCode: string, bid: Bid, responseMediaType = null) {
const metrics = useMetrics(bid.metrics);
metrics.checkpoint('addBidResponse');
adUnitCodesHandled[adUnitCode] = true;
- if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid))) {
+ if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid, { responseMediaType }))) {
addBidResponse(adUnitCode, bid);
} else {
addBidResponse.reject(adUnitCode, bid, REJECTION_REASON.INVALID)
@@ -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) {
@@ -353,7 +345,10 @@ export function newBidder(spec: BidderSpec) {
bid.deferBilling = bidRequest.deferBilling;
bid.deferRendering = bid.deferBilling && (bidResponse.deferRendering ?? typeof spec.onBidBillable !== 'function');
const prebidBid: Bid = Object.assign(createBid(bidRequest), bid, pick(bidRequest, Object.keys(TIDS)));
- addBidWithCode(bidRequest.adUnitCode, prebidBid);
+ const responseMediaType = Object.prototype.hasOwnProperty.call(bidResponse, 'mediaType')
+ ? bidResponse.mediaType
+ : null;
+ addBidWithCode(bidRequest.adUnitCode, prebidBid, responseMediaType);
} else {
logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bidResponse.requestId}. Ignoring.`);
addBidResponse.reject(null, bidResponse, REJECTION_REASON.INVALID_REQUEST_ID);
@@ -390,7 +385,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 +407,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 +424,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 +479,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 +608,6 @@ export const registerSyncInner = hook('async', function(spec: BidderSpec {
-}, 'addPaapiConfig');
-
declare module '../bidfactory' {
interface BannerBidProperties {
width?: number;
@@ -661,7 +650,7 @@ function validBidSize(adUnitCode, bid: BannerBid, { index = auctionManager.index
}
// Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored.
-export function isValid(adUnitCode: string, bid: Bid, { index = auctionManager.index } = {}) {
+export function isValid(adUnitCode: string, bid: Bid, { index = auctionManager.index, responseMediaType = bid.mediaType } = {}) {
function hasValidKeys() {
const bidKeys = Object.keys(bid);
return COMMON_BID_RESPONSE_KEYS.every(key => bidKeys.includes(key) && ![undefined, null].includes(bid[key]));
@@ -686,6 +675,21 @@ export function isValid(adUnitCode: string, bid: Bid, { index = auctionManager.i
return false;
}
+ const auctionOptions = config.getConfig('auctionOptions') || {};
+ const rejectUnknownMediaTypes = auctionOptions.rejectUnknownMediaTypes === true;
+ const rejectInvalidMediaTypes = auctionOptions.rejectInvalidMediaTypes !== false;
+ const mediaTypes = index.getMediaTypes(bid);
+ if (mediaTypes && Object.keys(mediaTypes).length > 0) {
+ if (responseMediaType == null && rejectUnknownMediaTypes) {
+ logError(errorMessage(`Bid mediaType is required. Allowed: ${Object.keys(mediaTypes).join(', ')}`));
+ return false;
+ }
+ if (responseMediaType != null && rejectInvalidMediaTypes && !mediaTypes.hasOwnProperty(responseMediaType)) {
+ logError(errorMessage(`Bid mediaType '${responseMediaType}' is not supported by the ad unit. Allowed: ${Object.keys(mediaTypes).join(', ')}`));
+ return false;
+ }
+ }
+
if (FEATURES.NATIVE && bid.mediaType === 'native' && !nativeBidIsValid(bid, { index })) {
logError(errorMessage('Native bid missing some required properties.'));
return false;
diff --git a/src/ajax.ts b/src/ajax.ts
index 986369c7a0f..a1eda919d42 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 8130d37e590..6a7a9643938 100644
--- a/src/auction.ts
+++ b/src/auction.ts
@@ -33,7 +33,7 @@ import { getMinBidCacheTTL, onMinBidCacheTTLChange } from './bidTTL.js';
import type { Bid, BidResponse } from "./bidfactory.ts";
import type { AdUnitCode, BidderCode, Identifier, ORTBFragments } from './types/common.d.ts';
import type { TargetingMap } from "./targeting.ts";
-import type { AdUnit } from "./adUnits.ts";
+import type { AdUnit, AdUnitDefinition } from "./adUnits.ts";
import type { MediaType } from "./mediaTypes.ts";
import type { VideoContext } from "./video.ts";
import { isActivityAllowed } from './activities/rules.js';
@@ -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.
*/
@@ -147,6 +143,18 @@ export interface AuctionOptionsConfig {
* to pre-10.12 rendering logic.
*/
legacyRender?: boolean;
+
+ /**
+ * When true, reject bids without a response `mediaType` when the ad unit has an explicit mediaTypes list.
+ * Default is false to preserve legacy behavior for responses that omit mediaType.
+ */
+ rejectUnknownMediaTypes?: boolean;
+
+ /**
+ * When true, reject bids with a response `mediaType` that does not match the ad unit's explicit mediaTypes list.
+ * Default is true; set to false to keep mismatched mediaType responses.
+ */
+ rejectInvalidMediaTypes?: boolean;
}
export interface PriceBucketConfig {
@@ -428,8 +436,8 @@ export function newAuction({ adUnits, adUnitCodes, callback, cbTimeout, labels,
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 +538,6 @@ export function auctionCallbacks(auctionDone, auctionInstance, { index = auction
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 {
@@ -666,6 +673,7 @@ declare module './bidfactory' {
}
interface BaseBid {
+ element?: AdUnitDefinition['element'];
/**
* true if this bid is for an interstitial slot.
*/
@@ -775,6 +783,7 @@ function getPreparedBidForAuction(bid: Partial, { index = auctionManager.in
const adUnit = index.getAdUnit(bid);
bid.instl = adUnit?.ortb2Imp?.instl === 1;
+ bid.element = adUnit?.element;
// a publisher-defined renderer can be used to render bids
const bidRenderer = index.getBidRequest(bid)?.renderer || adUnit.renderer;
diff --git a/src/config.ts b/src/config.ts
index 01874d74329..edb30c14c12 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -64,7 +64,7 @@ function attachProperties(config, useDefaultValues = true) {
} : {}
const validateauctionOptions = (() => {
- const boolKeys = ['secondaryBidders', 'suppressStaleRender', 'suppressExpiredRender', 'legacyRender'];
+ const boolKeys = ['suppressStaleRender', 'suppressExpiredRender', 'legacyRender', 'rejectUnknownMediaTypes', 'rejectInvalidMediaTypes'];
const arrKeys = ['secondaryBidders']
const allKeys = [].concat(boolKeys).concat(arrKeys);
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/eventTrackers.js b/src/eventTrackers.js
index 561084a1a4a..306db1fe300 100644
--- a/src/eventTrackers.js
+++ b/src/eventTrackers.js
@@ -2,6 +2,7 @@ export const TRACKER_METHOD_IMG = 1;
export const TRACKER_METHOD_JS = 2;
export const EVENT_TYPE_IMPRESSION = 1;
export const EVENT_TYPE_WIN = 500;
+export const EVENT_TYPE_VIEWABLE = 2;
/**
* Returns a map from event type (EVENT_TYPE_*)
diff --git a/src/fpd/enrichment.ts b/src/fpd/enrichment.ts
index 107d98d9667..4d3f8327e63 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/native.ts b/src/native.ts
index f9e05d9ed34..c8e27fc6fcc 100644
--- a/src/native.ts
+++ b/src/native.ts
@@ -23,7 +23,7 @@ import {
import { NATIVE } from './mediaTypes.js';
import { getRenderingData } from './adRendering.js';
import { getCreativeRendererSource, PUC_MIN_VERSION } from './creativeRenderers.js';
-import { EVENT_TYPE_IMPRESSION, parseEventTrackers, TRACKER_METHOD_IMG, TRACKER_METHOD_JS } from './eventTrackers.js';
+import { EVENT_TYPE_IMPRESSION, EVENT_TYPE_VIEWABLE, parseEventTrackers, TRACKER_METHOD_IMG, TRACKER_METHOD_JS } from './eventTrackers.js';
import type { Link, NativeRequest, NativeResponse } from "./types/ortb/native.d.ts";
import type { Size } from "./types/common.d.ts";
import type { Ext } from "./types/ortb/common.d.ts";
@@ -350,14 +350,15 @@ export function fireNativeTrackers(message, bidResponse) {
if (message.action === 'click') {
fireClickTrackers(nativeResponse, message?.assetId);
} else {
- fireImpressionTrackers(nativeResponse);
+ fireImpressionTrackers(nativeResponse, bidResponse);
}
return message.action;
}
-export function fireImpressionTrackers(nativeResponse, { runMarkup = (mkup) => insertHtmlIntoIframe(mkup), fetchURL = triggerPixel } = {}) {
+export function fireImpressionTrackers(nativeResponse, bidResponse, { runMarkup = (mkup) => insertHtmlIntoIframe(mkup), fetchURL = triggerPixel } = {}) {
+ const filteredEventTrackers = filterEventTrackers(nativeResponse, bidResponse);
let { [TRACKER_METHOD_IMG]: img = [], [TRACKER_METHOD_JS]: js = [] } = parseEventTrackers(
- nativeResponse.eventtrackers || []
+ filteredEventTrackers || []
)[EVENT_TYPE_IMPRESSION] || {};
if (nativeResponse.imptrackers) {
@@ -398,6 +399,20 @@ export function fireClickTrackers(nativeResponse, assetId = null, { fetchURL = t
}
}
+export function filterEventTrackers(nativeResponse, bid) {
+ const DEFAULT_ALLOWED_TRACKERS = [
+ { event: EVENT_TYPE_IMPRESSION, methods: [TRACKER_METHOD_IMG, TRACKER_METHOD_JS] },
+ { event: EVENT_TYPE_VIEWABLE, methods: [TRACKER_METHOD_IMG, TRACKER_METHOD_JS] },
+ ];
+ const mediaTypes = auctionManager.index.getMediaTypes(bid) || {};
+ const nativeMediaType = mediaTypes.native || {};
+ const requestEventTrackers = nativeMediaType.ortb?.eventtrackers || DEFAULT_ALLOWED_TRACKERS;
+
+ const { eventtrackers = [] } = nativeResponse || {};
+
+ return eventtrackers.filter(tracker => requestEventTrackers.some(requestTracker => requestTracker.event === tracker.event && requestTracker.methods.includes(tracker.method)));
+}
+
export function setNativeResponseProperties(bid, adUnit) {
const nativeOrtbRequest = adUnit?.nativeOrtbRequest;
const nativeOrtbResponse = bid.native?.ortb;
diff --git a/src/prebid.ts b/src/prebid.ts
index 5d37a6dcce8..c2d21b9c4eb 100644
--- a/src/prebid.ts
+++ b/src/prebid.ts
@@ -28,7 +28,7 @@ import { listenMessagesFromCreative } from './secureCreatives.js';
import { userSync } from './userSync.js';
import { config } from './config.js';
import { auctionManager } from './auctionManager.js';
-import { isBidUsable, type SlotMatchingFn, targeting } from './targeting.js';
+import { isBidUsable, targeting } from './targeting.js';
import { hook, wrapHook } from './hook.js';
import { loadSession } from './debugging.js';
import { storageCallbacks } from './storageManager.js';
@@ -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();
@@ -610,14 +610,13 @@ addApiMethod('getBidResponsesForAdUnitCode', getBidResponsesForAdUnitCode);
/**
* Set query string targeting on one or more GPT ad units.
* @param adUnit a single `adUnit.code` or multiple.
- * @param customSlotMatching gets a GoogleTag slot and returns a filter function for adUnitCode, so you can decide to match on either eg. return slot => { return adUnitCode => { return slot.getSlotElementId() === 'myFavoriteDivId'; } };
*/
-function setTargetingForGPTAsync(adUnit?: AdUnitCode | AdUnitCode[], customSlotMatching?: SlotMatchingFn) {
+function setTargetingForGPTAsync(adUnit?: AdUnitCode | AdUnitCode[]) {
if (!isGptPubadsDefined()) {
logError('window.googletag is not defined on the page');
return;
}
- targeting.setTargetingForGPT(adUnit, customSlotMatching);
+ targeting.setTargetingForGPT(adUnit);
}
addApiMethod('setTargetingForGPTAsync', setTargetingForGPTAsync);
@@ -954,21 +953,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 cbcf8e85bdd..4c81217b215 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,8 @@ import {
} from './adRendering.js';
import { getCreativeRendererSource, PUC_MIN_VERSION } from './creativeRenderers.js';
import { PbPromise } from './utils/promise.js';
+import { getAdUnitElement } from './utils/adUnits.js';
+import { auctionManager } from './auctionManager.js';
const { REQUEST, RESPONSE, NATIVE, EVENT } = MESSAGES;
@@ -70,10 +71,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();
}
}
@@ -167,7 +166,7 @@ export function resizeAnchor(ins, width, height) {
})
}
-export function resizeRemoteCreative({ instl, adId, adUnitCode, width, height }) {
+export function resizeRemoteCreative({ instl, element, adId, adUnitCode, width, height }) {
// do not resize interstitials - the creative frame takes the full screen and sizing of the ad should
// be handled within it.
if (instl) return;
@@ -190,7 +189,7 @@ export function resizeRemoteCreative({ instl, adId, adUnitCode, width, height })
function getElementByAdUnit(elmType) {
const id = getElementIdBasedOnAdServer(adId, adUnitCode);
- const parentDivEle = document.getElementById(id);
+ const parentDivEle = id == null ? getAdUnitElement({ element, adUnitCode }) : document.getElementById(id);
return parentDivEle && parentDivEle.querySelector(elmType);
}
@@ -207,13 +206,16 @@ export function resizeRemoteCreative({ instl, adId, adUnitCode, width, height })
return apnId;
}
}
- return adUnitCode;
}
function getDfpElementId(adId) {
const slot = window.googletag.pubads().getSlots().find(slot => {
- return slot.getTargetingKeys().find(key => {
- return slot.getTargeting(key).includes(adId);
+ const targetingMap = slot.getConfig('targeting');
+ const keys = Object.keys(targetingMap);
+
+ return keys.find(key => {
+ const values = targetingMap[key];
+ return values.includes(adId);
});
});
return slot ? slot.getSlotElementId() : null;
diff --git a/src/targeting.ts b/src/targeting.ts
index 371436e614a..d035bb1713e 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,
@@ -133,13 +132,12 @@ export function sortByDealAndPriceBucketOrCpm(useCpm = false) {
* Return a map where each code in `adUnitCodes` maps to a list of GPT slots that match it.
*
* @param adUnitCodes
- * @param customSlotMatching
* @param getSlots
*/
-export function getGPTSlotsForAdUnits(adUnitCodes: AdUnitCode[], customSlotMatching, getSlots = () => window.googletag.pubads().getSlots()): ByAdUnit {
+export function getGPTSlotsForAdUnits(adUnitCodes: AdUnitCode[], getSlots = () => window.googletag.pubads().getSlots()): ByAdUnit {
return getSlots().reduce((auToSlots, slot) => {
- const customMatch = isFn(customSlotMatching) && customSlotMatching(slot);
- Object.keys(auToSlots).filter(isFn(customMatch) ? customMatch : isAdUnitCodeMatchingSlot(slot)).forEach(au => auToSlots[au].push(slot));
+ Object.keys(auToSlots).filter(isAdUnitCodeMatchingSlot(slot))
+ .forEach(au => auToSlots[au].push(slot));
return auToSlots;
}, Object.fromEntries(adUnitCodes.map(au => [au, []])));
}
@@ -306,13 +304,13 @@ export function newTargeting(auctionManager) {
return flatTargeting;
},
- setTargetingForGPT: hook('sync', function (adUnit?: AdUnitCode | AdUnitCode[], customSlotMatching?: SlotMatchingFn) {
+ setTargetingForGPT: hook('sync', function (adUnit?: AdUnitCode | AdUnitCode[]) {
// get our ad unit codes
const targetingSet: ByAdUnit = targeting.getAllTargeting(adUnit);
const resetMap = Object.fromEntries(pbTargetingKeys.map(key => [key, null]));
- Object.entries(getGPTSlotsForAdUnits(Object.keys(targetingSet), customSlotMatching)).forEach(([targetId, slots]) => {
+ Object.entries(getGPTSlotsForAdUnits(Object.keys(targetingSet))).forEach(([targetId, slots]) => {
slots.forEach(slot => {
// now set new targeting keys
Object.keys(targetingSet[targetId]).forEach(key => {
@@ -324,7 +322,8 @@ export function newTargeting(auctionManager) {
targetingSet[targetId][key] = value;
});
logMessage(`Attempting to set targeting-map for slot: ${slot.getSlotElementId()} with targeting-map:`, targetingSet[targetId]);
- slot.updateTargetingFromMap(Object.assign({}, resetMap, targetingSet[targetId]))
+ const targetingMap = Object.assign({}, resetMap, targetingSet[targetId]);
+ slot.setConfig({ targeting: targetingMap } as any);
lock.lock(targetingSet[targetId]);
})
})
@@ -678,7 +677,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 f9ca35de8a7..65cb3713cce 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -772,7 +772,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);
@@ -810,7 +810,9 @@ export const compareCodeAndSlot = (slot, adUnitCode) => slot.getAdUnitPath() ===
* @return filter function
*/
export function isAdUnitCodeMatchingSlot(slot) {
- return (adUnitCode) => compareCodeAndSlot(slot, adUnitCode);
+ const customGptSlotMatching = config.getConfig('customGptSlotMatching');
+ const match = isFn(customGptSlotMatching) && customGptSlotMatching(slot);
+ return isFn(match) ? match : (adUnitCode) => compareCodeAndSlot(slot, adUnitCode);
}
/**
diff --git a/src/utils/adUnits.ts b/src/utils/adUnits.ts
new file mode 100644
index 00000000000..d9f4196e19c
--- /dev/null
+++ b/src/utils/adUnits.ts
@@ -0,0 +1,21 @@
+import type { AdUnitDefinition } from "../adUnits.ts";
+import type { BidRequest } from "../adapterManager.ts";
+import type { Bid } from "../bidfactory.ts";
+
+export function getAdUnitElement(bidRequest: BidRequest): HTMLElement
+export function getAdUnitElement(bidResponse: Bid): HTMLElement
+export function getAdUnitElement(adUnit: AdUnitDefinition): HTMLElement
+export function getAdUnitElement(target: {
+ code?: string,
+ adUnitCode?: string,
+ element?: HTMLElement
+}): HTMLElement | null {
+ if (target.element != null) {
+ return target.element;
+ }
+ const id = target.adUnitCode ?? target.code;
+ if (id) {
+ return document.getElementById(id);
+ }
+ return null;
+}
diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js
index 388ea2c5e2d..58151526325 100644
--- a/test/spec/auctionmanager_spec.js
+++ b/test/spec/auctionmanager_spec.js
@@ -105,6 +105,10 @@ function mockBidRequest(bid, opts) {
const defaultMediaType = {
banner: {
sizes: [[300, 250], [300, 600]]
+ },
+ video: {
+ context: 'outstream',
+ renderer: {}
}
}
const mediaType = (opts && opts.mediaType) ? opts.mediaType : defaultMediaType;
@@ -836,7 +840,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']
});
@@ -1159,7 +1163,7 @@ describe('auctionmanager.js', function () {
bids[0],
{
bidderCode: BIDDER_CODE,
- mediaType: 'video-outstream',
+ mediaType: 'video',
}
);
spec.interpretResponse.returns(bids1);
@@ -1278,6 +1282,12 @@ describe('auctionmanager.js', function () {
expect(auction.getBidsReceived()[0].ttlBuffer).to.eql(0);
});
+ it('sets bidResponse.element from adUnit.element', () => {
+ adUnits[0].element = 'test';
+ auction.callBids();
+ expect(auction.getBidsReceived()[0].element).to.equal('test');
+ });
+
[
{
request: 1,
diff --git a/test/spec/libraries/bidViewabilityPixels_spec.js b/test/spec/libraries/bidViewabilityPixels_spec.js
new file mode 100644
index 00000000000..05f248c30ba
--- /dev/null
+++ b/test/spec/libraries/bidViewabilityPixels_spec.js
@@ -0,0 +1,178 @@
+import { fireViewabilityPixels, getViewabilityTrackersFromBid } from 'libraries/bidViewabilityPixels/index.js';
+import * as utils from 'src/utils.js';
+import * as sinon from 'sinon';
+import { expect } from 'chai';
+import { EVENT_TYPE_IMPRESSION, EVENT_TYPE_VIEWABLE, TRACKER_METHOD_IMG, TRACKER_METHOD_JS } from 'src/eventTrackers.js';
+import { auctionManager } from 'src/auctionManager.js';
+
+const VIEWABILITY_PIXEL_URLS = [
+ 'https://domain-1.com/end-point?a=1',
+ 'https://domain-2.com/end-point/',
+ 'https://domain-3.com/end-point?a=1'
+];
+
+const bidWithViewabilityTrackers = {
+ adUnitCode: 'test-unit',
+ bidder: 'test-bidder',
+ eventtrackers: VIEWABILITY_PIXEL_URLS.map(url => ({
+ event: EVENT_TYPE_VIEWABLE,
+ method: TRACKER_METHOD_IMG,
+ url
+ }))
+};
+
+describe('bidViewabilityPixels library', function () {
+ let sandbox;
+ let triggerPixelSpy;
+ let insertHtmlIntoIframeSpy;
+
+ beforeEach(function () {
+ sandbox = sinon.createSandbox();
+ triggerPixelSpy = sandbox.spy(utils, 'triggerPixel');
+ insertHtmlIntoIframeSpy = sandbox.spy(utils, 'insertHtmlIntoIframe');
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
+ describe('getViewabilityTrackersFromBid', function () {
+ it('should return { img: [], js: [] } when bid is null, undefined, or has no valid eventtrackers', function () {
+ const empty = { img: [], js: [] };
+ expect(getViewabilityTrackersFromBid(null)).to.deep.equal(empty);
+ expect(getViewabilityTrackersFromBid(undefined)).to.deep.equal(empty);
+ expect(getViewabilityTrackersFromBid({ adUnitCode: 'x' })).to.deep.equal(empty);
+ expect(getViewabilityTrackersFromBid({ eventtrackers: {} })).to.deep.equal(empty);
+ expect(getViewabilityTrackersFromBid({ eventtrackers: 'trackers' })).to.deep.equal(empty);
+ expect(getViewabilityTrackersFromBid({ eventtrackers: [] })).to.deep.equal(empty);
+ });
+
+ it('should return img and js URLs for viewable trackers', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://img.com' },
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_JS, url: 'https://js.com' }
+ ]
+ };
+ expect(getViewabilityTrackersFromBid(bid)).to.deep.equal({
+ img: ['https://img.com'],
+ js: ['https://js.com']
+ });
+ });
+
+ it('should return only viewable trackers when eventtrackers has mixed event types', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://viewable.com' },
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'https://impression.com' }
+ ]
+ };
+ expect(getViewabilityTrackersFromBid(bid)).to.deep.equal({
+ img: ['https://viewable.com'],
+ js: []
+ });
+ });
+
+ it('should return only js when viewable trackers have JS method only', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_JS, url: 'https://viewable-js.com' }
+ ]
+ };
+ expect(getViewabilityTrackersFromBid(bid)).to.deep.equal({
+ img: [],
+ js: ['https://viewable-js.com']
+ });
+ });
+ });
+
+ describe('fireViewabilityPixels', function () {
+ it('should not call triggerPixel or insertHtmlIntoIframe when bid has no eventtrackers', function () {
+ fireViewabilityPixels({ adUnitCode: 'x' });
+ expect(triggerPixelSpy.callCount).to.equal(0);
+ expect(insertHtmlIntoIframeSpy.callCount).to.equal(0);
+ });
+
+ it('should not call triggerPixel or insertHtmlIntoIframe when eventtrackers is empty array', function () {
+ fireViewabilityPixels({ eventtrackers: [] });
+ expect(triggerPixelSpy.callCount).to.equal(0);
+ expect(insertHtmlIntoIframeSpy.callCount).to.equal(0);
+ });
+
+ it('should fire one pixel per viewable img URL in eventtrackers', function () {
+ fireViewabilityPixels(bidWithViewabilityTrackers);
+ expect(triggerPixelSpy.callCount).to.equal(VIEWABILITY_PIXEL_URLS.length);
+ VIEWABILITY_PIXEL_URLS.forEach((url, i) => {
+ expect(triggerPixelSpy.getCall(i).args[0]).to.equal(url);
+ });
+ });
+
+ it('should fire viewable JS trackers via insertHtmlIntoIframe with script tag', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_JS, url: 'https://viewable-js.com' }
+ ]
+ };
+ fireViewabilityPixels(bid);
+ expect(triggerPixelSpy.callCount).to.equal(0);
+ expect(insertHtmlIntoIframeSpy.callCount).to.equal(1);
+ expect(insertHtmlIntoIframeSpy.getCall(0).args[0]).to.include('script async src="https://viewable-js.com"');
+ });
+
+ it('should fire both img (triggerPixel) and js (insertHtmlIntoIframe) viewable trackers', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://img.com' },
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_JS, url: 'https://js.com' }
+ ]
+ };
+ fireViewabilityPixels(bid);
+ expect(triggerPixelSpy.callCount).to.equal(1);
+ expect(triggerPixelSpy.getCall(0).args[0]).to.equal('https://img.com');
+ expect(insertHtmlIntoIframeSpy.callCount).to.equal(1);
+ expect(insertHtmlIntoIframeSpy.getCall(0).args[0]).to.include('script async src="https://js.com"');
+ });
+
+ it('should only fire EVENT_TYPE_VIEWABLE URLs', function () {
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://viewable-img.com' },
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'https://impression.com' }
+ ]
+ };
+ fireViewabilityPixels(bid);
+ expect(triggerPixelSpy.callCount).to.equal(1);
+ expect(triggerPixelSpy.getCall(0).args[0]).to.equal('https://viewable-img.com');
+ });
+
+ describe('when bid has native response with eventtrackers (viewable)', function () {
+ let indexStub;
+ let getMediaTypesStub;
+
+ beforeEach(function () {
+ getMediaTypesStub = sinon.stub();
+ indexStub = sandbox.stub(auctionManager, 'index').get(() => ({ getMediaTypes: getMediaTypesStub }));
+ });
+
+ it('should fire viewable trackers from bid.native.ortb.eventtrackers in addition to bid.eventtrackers', function () {
+ getMediaTypesStub.returns({});
+ const bid = {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://from-bid.com' }
+ ],
+ native: {
+ ortb: {
+ eventtrackers: [
+ { event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url: 'https://from-native.com' }
+ ]
+ }
+ }
+ };
+ fireViewabilityPixels(bid);
+ expect(triggerPixelSpy.callCount).to.equal(2);
+ expect(triggerPixelSpy.getCall(0).args[0]).to.equal('https://from-bid.com');
+ expect(triggerPixelSpy.getCall(1).args[0]).to.equal('https://from-native.com');
+ });
+ });
+ });
+});
diff --git a/test/spec/libraries/dnt_spec.js b/test/spec/libraries/dnt_spec.js
deleted file mode 100644
index f2415dfae6e..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/percentInView_spec.js b/test/spec/libraries/percentInView_spec.js
index 7405e95f95d..fd3f9b5ea20 100644
--- a/test/spec/libraries/percentInView_spec.js
+++ b/test/spec/libraries/percentInView_spec.js
@@ -1,6 +1,23 @@
-import { getViewportOffset } from '../../../libraries/percentInView/percentInView.js';
+import {
+ getViewportOffset,
+ intersections,
+ mkIntersectionHook,
+ percentInView,
+ viewportIntersections,
+} from '../../../libraries/percentInView/percentInView.js';
+import * as bbox from 'libraries/boundingClientRect/boundingClientRect';
+
+import { defer } from 'src/utils/promise.js';
describe('percentInView', () => {
+ let sandbox;
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+
describe('getViewportOffset', () => {
function mockWindow(offsets = []) {
let win, leaf, child;
@@ -17,6 +34,7 @@ describe('percentInView', () => {
}
return leaf;
}
+
it('returns 0, 0 for the top window', () => {
expect(getViewportOffset(mockWindow())).to.eql({ x: 0, y: 0 });
});
@@ -37,4 +55,218 @@ describe('percentInView', () => {
expect(getViewportOffset(win)).to.eql({ x: 0, y: 0 });
});
});
+
+ async function delay(ms = 10) {
+ await new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+ describe('intersections', () => {
+ let callback, obs, nakedObs, mkObserver, el;
+ beforeEach(() => {
+ el = document.createElement('div');
+ nakedObs = sinon.stub();
+ nakedObs.observe = sinon.stub();
+ mkObserver = sinon.stub().callsFake((cb) => {
+ callback = cb;
+ return nakedObs;
+ });
+ obs = intersections(mkObserver);
+ });
+ describe('when mkObserver throws', () => {
+ beforeEach(() => {
+ mkObserver = sinon.stub().callsFake(() => {
+ throw new Error();
+ });
+ obs = intersections(mkObserver);
+ });
+ it('getIntersection should return undef', () => {
+ expect(obs.getIntersection({})).to.not.exist;
+ });
+
+ it('observe should resolve', async () => {
+ await obs.observe({});
+ });
+ });
+
+ it('observe should reject if the element cannot be observed', async () => {
+ let err = new Error();
+ nakedObs.observe.throws(err);
+ try {
+ await obs.observe(null);
+ } catch (e) {
+ expect(e).to.eql(err);
+ return;
+ }
+ sinon.assert.fail('promise should reject');
+ });
+ it('does not observe the same element more than once', () => {
+ obs.observe(el);
+ obs.observe(el);
+ sinon.assert.calledOnce(nakedObs.observe);
+ });
+ it('getIntersection should return undefined if the element is not observed', () => {
+ expect(obs.getIntersection(el)).to.not.exist;
+ });
+ it('observe should resolve to latest intersection entry', () => {
+ let pm = obs.observe(el);
+ let entry = {
+ target: el,
+ time: 100
+ };
+ callback([entry, {
+ target: el,
+ time: 50
+ }]);
+ return pm.then(result => {
+ expect(result).to.eql(entry);
+ });
+ });
+ it('observe should resolve immediately if an entry is available', () => {
+ const entry = {
+ target: el,
+ time: 10
+ };
+ callback([entry]);
+ const pm = obs.observe(el);
+ callback([{
+ target: el,
+ time: 20
+ }]);
+ return pm.then((result) => {
+ expect(result).to.eql(entry);
+ });
+ });
+ it('should ignore stale entries', async () => {
+ const entry = {
+ target: el,
+ time: 100
+ };
+ obs.observe(el);
+ callback([entry]);
+ callback([{
+ target: el,
+ time: 10
+ }]);
+ expect(obs.getIntersection(el)).to.eql(entry);
+ });
+
+ it('should not resolve until the targeted element has intersected', async () => {
+ const entry = {
+ target: el,
+ time: 100
+ };
+ const pm = obs.observe(el);
+ callback([{
+ target: {},
+ time: 20
+ }]);
+ await delay();
+ callback([entry]);
+ expect(await pm).to.eql(entry);
+ });
+ });
+
+ describe('intersection hook', () => {
+ let intersections, hook, next, request;
+ beforeEach(() => {
+ next = sinon.stub();
+ intersections = {
+ observe: sinon.stub()
+ };
+ hook = mkIntersectionHook(intersections);
+ request = {};
+ });
+
+ it('should observe elements for every ad unit', async () => {
+ request.adUnits = [{
+ element: 'el1'
+ }, {
+ code: 'el2'
+ }];
+ sandbox.stub(document, 'getElementById').returns('el2');
+ hook(next, request);
+ sinon.assert.calledWith(intersections.observe, 'el1');
+ sinon.assert.calledWith(intersections.observe, 'el2');
+ await delay();
+ sinon.assert.calledWith(next, request);
+ });
+
+ describe('promise resolution', () => {
+ let adUnits;
+ beforeEach(() => {
+ adUnits = {
+ el1: {
+ element: 'el1',
+ df: defer()
+ },
+ el2: {
+ element: 'el2',
+ df: defer()
+ }
+ };
+ request.adUnits = Object.values(adUnits);
+ intersections.observe.callsFake((element) => adUnits[element].df.promise);
+ });
+ it('should wait for all promises to resolve', async () => {
+ hook(next, request);
+ sinon.assert.notCalled(next);
+ adUnits.el1.df.resolve();
+ await delay();
+ sinon.assert.notCalled(next);
+ adUnits.el2.df.resolve();
+ await delay();
+ sinon.assert.calledWith(next, request);
+ });
+
+ it('should still continue if some promises reject', async () => {
+ hook(next, request);
+ adUnits.el1.df.reject();
+ await delay();
+ sinon.assert.notCalled(next);
+ adUnits.el2.df.resolve();
+ await delay();
+ sinon.assert.calledWith(next, request);
+ });
+
+ it('should continue if promises never resolve', async () => {
+ hook(next, request);
+ await delay(100);
+ sinon.assert.called(next);
+ });
+
+ it('should not delay if there are no elements to observe', async () => {
+ request.adUnits = [];
+ hook(next, request);
+ await delay();
+ sinon.assert.called(next);
+ })
+ });
+ });
+
+ describe('percentInView', () => {
+ let intersection;
+ beforeEach(() => {
+ sandbox.stub(viewportIntersections, 'getIntersection').callsFake(() => intersection);
+ sandbox.stub(viewportIntersections, 'observe');
+ sandbox.stub(bbox, 'getBoundingClientRect');
+ });
+
+ it('does not use intersection if w/h are relevant', () => {
+ bbox.getBoundingClientRect.returns({
+ width: 0,
+ height: 0,
+ left: -50,
+ top: -100,
+ });
+ intersection = {
+ boundingClientRect: {
+ width: 0,
+ height: 0,
+ },
+ isIntersecting: true,
+ intersectionRatio: 1
+ };
+ expect(percentInView({}, { w: 100, h: 200 })).to.not.eql(100);
+ });
+ });
});
diff --git a/test/spec/libraries/placementPositionInfo_spec.js b/test/spec/libraries/placementPositionInfo_spec.js
index 91aee5c6d81..bfd886b8898 100644
--- a/test/spec/libraries/placementPositionInfo_spec.js
+++ b/test/spec/libraries/placementPositionInfo_spec.js
@@ -3,6 +3,7 @@ import * as utils from '../../../src/utils.js';
import * as boundingClientRectLib from '../../../libraries/boundingClientRect/boundingClientRect.js';
import * as percentInViewLib from '../../../libraries/percentInView/percentInView.js';
import * as winDimensions from 'src/utils/winDimensions.js';
+import * as adUnits from 'src/utils/adUnits';
import assert from 'assert';
import sinon from 'sinon';
@@ -80,7 +81,7 @@ describe('placementPositionInfo', function () {
beforeEach(function () {
mockElement = { id: 'test-ad-unit' };
- mockDocument.getElementById.returns(mockElement);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(mockElement);
getBoundingClientRectStub.returns({
top: 100,
@@ -162,7 +163,7 @@ describe('placementPositionInfo', function () {
});
it('should handle null element gracefully', function () {
- mockDocument.getElementById.returns(null);
+ adUnits.getAdUnitElement.returns(null);
const bidReq = {
adUnitCode: 'non-existent-unit',
@@ -177,7 +178,7 @@ describe('placementPositionInfo', function () {
});
it('should not call getViewability when element is null', function () {
- mockDocument.getElementById.returns(null);
+ adUnits.getAdUnitElement.returns(null);
const bidReq = {
adUnitCode: 'non-existent-unit',
@@ -400,7 +401,7 @@ describe('placementPositionInfo', function () {
describe('iframe coordinate translation', function () {
beforeEach(() => {
- mockDocument.getElementById = sandbox.stub().returns({ id: 'test' });
+ sandbox.stub(adUnits, 'getAdUnitElement').returns({ id: 'test' })
mockWindow.innerHeight = 1000;
mockDocument.body = {
scrollHeight: 2000, offsetHeight: 1800
diff --git a/test/spec/libraries/storageDisclosure_spec.js b/test/spec/libraries/storageDisclosure_spec.js
index fa345b6115c..98a98700484 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 7c861c0723f..6c7c98d197c 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 917b39a8eb4..34afb59ec4a 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';
@@ -341,11 +340,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];
}
@@ -418,7 +415,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/adnuntiusAnalyticsAdapter_spec.js b/test/spec/modules/adnuntiusAnalyticsAdapter_spec.js
index 55cddbb0dd2..0fc8c700aff 100644
--- a/test/spec/modules/adnuntiusAnalyticsAdapter_spec.js
+++ b/test/spec/modules/adnuntiusAnalyticsAdapter_spec.js
@@ -2,7 +2,7 @@ import adnAnalyticsAdapter, { BID_WON_TIMEOUT } from 'modules/adnuntiusAnalytics
import { AD_RENDER_FAILED_REASON, EVENTS, STATUS } from 'src/constants.js';
import { config } from 'src/config.js';
import { server } from 'test/mocks/xhr.js';
-import { setConfig } from 'modules/currency.js';
+import * as adUnits from 'src/utils/adUnits';
const events = require('src/events');
const utils = require('src/utils');
@@ -301,7 +301,7 @@ describe('Adnuntius analytics adapter', function () {
}
sandbox.stub(events, 'getEvents').returns([]);
sandbox.stub(utils, 'timestamp').returns(1519149562416);
- sandbox.stub(document, 'getElementById').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
clock = sandbox.useFakeTimers(1519767013781);
});
diff --git a/test/spec/modules/adoceanBidAdapter_spec.js b/test/spec/modules/adoceanBidAdapter_spec.js
index fe0096bf91b..4ab511a5a2d 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 e833666ef62..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 95c40d66bb1..7b6e808dcaa 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 2c5d279c7bb..9ac4e762d9b 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/bidViewabilityIO_spec.js b/test/spec/modules/bidViewabilityIO_spec.js
index 947d9227ca5..f76a0c6230b 100644
--- a/test/spec/modules/bidViewabilityIO_spec.js
+++ b/test/spec/modules/bidViewabilityIO_spec.js
@@ -4,6 +4,9 @@ import * as utils from 'src/utils.js';
import * as sinon from 'sinon';
import { expect } from 'chai';
import { EVENTS } from 'src/constants.js';
+import { EVENT_TYPE_VIEWABLE, TRACKER_METHOD_IMG } from 'src/eventTrackers.js';
+import * as bidViewability from '../../../modules/bidViewability.js';
+import adapterManager from '../../../src/adapterManager.js';
describe('#bidViewabilityIO', function() {
const makeElement = (id) => {
@@ -101,6 +104,71 @@ describe('#bidViewabilityIO', function() {
});
})
+ describe('viewability pixels', function() {
+ let sandbox;
+ let triggerPixelSpy;
+ const mockObserver = { unobserve: sinon.spy() };
+ const mockEntry = { target: makeElement('pixel_target_id') };
+
+ const VIEWABILITY_PIXEL_URLS = [
+ 'https://io-viewable-1.com/pixel',
+ 'https://io-viewable-2.com/track'
+ ];
+
+ const bidWithEventTrackers = {
+ adUnitCode: 'banner_id',
+ mediaType: 'banner',
+ width: 728,
+ height: 90,
+ eventtrackers: VIEWABILITY_PIXEL_URLS.map(url => ({ event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url }))
+ };
+
+ beforeEach(function() {
+ sandbox = sinon.createSandbox();
+ triggerPixelSpy = sandbox.spy(utils, ['triggerPixel']);
+ });
+
+ afterEach(function() {
+ sandbox.restore();
+ });
+
+ it('fires viewability pixels when markViewed callback runs with bid that has eventTrackers (EVENT_TYPE_VIEWABLE)', function() {
+ const func = bidViewabilityIO.markViewed(bidWithEventTrackers, mockEntry, mockObserver);
+ func();
+ expect(triggerPixelSpy.callCount).to.equal(VIEWABILITY_PIXEL_URLS.length);
+ VIEWABILITY_PIXEL_URLS.forEach((url, i) => {
+ expect(triggerPixelSpy.getCall(i).args[0]).to.equal(url);
+ });
+ });
+
+ it('does not fire pixels when bid has empty eventTrackers', function() {
+ const bidWithEmptyTrackers = { ...banner_bid, eventtrackers: [] };
+ const func = bidViewabilityIO.markViewed(bidWithEmptyTrackers, mockEntry, mockObserver);
+ func();
+ expect(triggerPixelSpy.callCount).to.equal(0);
+ });
+
+ it('should call onBidViewable', () => {
+ sandbox.stub(adapterManager, 'callBidViewableBidder');
+ const bid = {
+ bidder: 'mockBidder',
+ ...banner_bid
+ }
+ bidViewabilityIO.markViewed(bid, mockEntry, mockObserver)();
+ sinon.assert.calledWith(adapterManager.callBidViewableBidder, 'mockBidder', bid);
+ });
+
+ it('should call the triggerBilling function if the viewable bid has deferBilling set to true', function() {
+ sandbox.stub(adapterManager, 'triggerBilling');
+ const bid = {
+ ...banner_bid,
+ deferBilling: true
+ }
+ bidViewabilityIO.markViewed(bid, mockEntry, mockObserver)();
+ sinon.assert.called(adapterManager.triggerBilling);
+ });
+ })
+
describe('viewCallbackFactory tests', function() {
let sandbox;
diff --git a/test/spec/modules/bidViewability_spec.js b/test/spec/modules/bidViewability_spec.js
index 3c64d1e6781..11257c0d03a 100644
--- a/test/spec/modules/bidViewability_spec.js
+++ b/test/spec/modules/bidViewability_spec.js
@@ -8,6 +8,7 @@ import * as prebidGlobal from 'src/prebidGlobal.js';
import { EVENTS } from 'src/constants.js';
import adapterManager, { gdprDataHandler, uspDataHandler } from 'src/adapterManager.js';
import parse from 'url-parse';
+import { EVENT_TYPE_VIEWABLE, TRACKER_METHOD_IMG } from 'src/eventTrackers.js';
const GPT_SLOT = {
getAdUnitPath() {
@@ -23,6 +24,12 @@ const EVENT_OBJ = {
slot: GPT_SLOT
}
+const VIEWABILITY_PIXEL_URLS = [
+ 'https://domain-1.com/end-point?a=1',
+ 'https://domain-2.com/end-point/',
+ 'https://domain-3.com/end-point?a=1'
+];
+
const PBJS_WINNING_BID = {
'adUnitCode': '/harshad/Jan/2021/',
'bidderCode': 'pubmatic',
@@ -39,11 +46,7 @@ const PBJS_WINNING_BID = {
'creativeId': 'id',
'netRevenue': true,
'currency': 'USD',
- 'vurls': [
- 'https://domain-1.com/end-point?a=1',
- 'https://domain-2.com/end-point/',
- 'https://domain-3.com/end-point?a=1'
- ]
+ 'eventtrackers': VIEWABILITY_PIXEL_URLS.map(url => ({ event: EVENT_TYPE_VIEWABLE, method: TRACKER_METHOD_IMG, url }))
};
describe('#bidViewability', function() {
@@ -55,22 +58,6 @@ describe('#bidViewability', function() {
pbjsWinningBid = Object.assign({}, PBJS_WINNING_BID);
});
- describe('isBidAdUnitCodeMatchingSlot', function() {
- it('match found by GPT Slot getAdUnitPath', function() {
- expect(bidViewability.isBidAdUnitCodeMatchingSlot(pbjsWinningBid, gptSlot)).to.equal(true);
- });
-
- it('match found by GPT Slot getSlotElementId', function() {
- pbjsWinningBid.adUnitCode = 'DIV-1';
- expect(bidViewability.isBidAdUnitCodeMatchingSlot(pbjsWinningBid, gptSlot)).to.equal(true);
- });
-
- it('match not found', function() {
- pbjsWinningBid.adUnitCode = 'DIV-10';
- expect(bidViewability.isBidAdUnitCodeMatchingSlot(pbjsWinningBid, gptSlot)).to.equal(false);
- });
- });
-
describe('getMatchingWinningBidForGPTSlot', function() {
let winningBidsArray;
let sandbox
@@ -89,159 +76,44 @@ describe('#bidViewability', function() {
sandbox.restore();
})
- it('should find a match by using customMatchFunction provided in config', function() {
- // Needs config to be passed with customMatchFunction
- const bidViewabilityConfig = {
- customMatchFunction(bid, slot) {
- return ('AD-' + slot.getAdUnitPath()) === bid.adUnitCode;
+ it('should find a match by using customGptSlotMatching provided in config', function() {
+ config.setConfig({
+ customGptSlotMatching: slot => {
+ return (adUnitCode) => ('AD-' + slot.getAdUnitPath()) === adUnitCode;
}
- };
+ });
const newWinningBid = Object.assign({}, PBJS_WINNING_BID, { adUnitCode: 'AD-' + PBJS_WINNING_BID.adUnitCode });
// Needs pbjs.getWinningBids to be implemented with match
winningBidsArray.push(newWinningBid);
- const wb = bidViewability.getMatchingWinningBidForGPTSlot(bidViewabilityConfig, gptSlot);
+ const wb = bidViewability.getMatchingWinningBidForGPTSlot(gptSlot);
expect(wb).to.deep.equal(newWinningBid);
+ config.resetConfig();
});
- it('should NOT find a match by using customMatchFunction provided in config', function() {
- // Needs config to be passed with customMatchFunction
- const bidViewabilityConfig = {
- customMatchFunction(bid, slot) {
- return ('AD-' + slot.getAdUnitPath()) === bid.adUnitCode;
- }
- };
- // Needs pbjs.getWinningBids to be implemented without match; winningBidsArray is set to empty in beforeEach
- const wb = bidViewability.getMatchingWinningBidForGPTSlot(bidViewabilityConfig, gptSlot);
+ it('should NOT find a match when customGptSlotMatching is set and no winning bid matches', function() {
+ config.setConfig({
+ customGptSlotMatching: slot => (adUnitCode) => ('AD-' + slot.getAdUnitPath()) === adUnitCode
+ });
+ // winningBidsArray is empty in beforeEach, so no bid matches
+ const wb = bidViewability.getMatchingWinningBidForGPTSlot(gptSlot);
expect(wb).to.equal(null);
+ config.resetConfig();
});
it('should find a match by using default matching function', function() {
- // Needs config to be passed without customMatchFunction
- // Needs pbjs.getWinningBids to be implemented with match
+ // No customGptSlotMatching in config; pbjs.getWinningBids returns matching bid
winningBidsArray.push(PBJS_WINNING_BID);
- const wb = bidViewability.getMatchingWinningBidForGPTSlot({}, gptSlot);
+ const wb = bidViewability.getMatchingWinningBidForGPTSlot(gptSlot);
expect(wb).to.deep.equal(PBJS_WINNING_BID);
});
it('should NOT find a match by using default matching function', function() {
- // Needs config to be passed without customMatchFunction
- // Needs pbjs.getWinningBids to be implemented without match; winningBidsArray is set to empty in beforeEach
- const wb = bidViewability.getMatchingWinningBidForGPTSlot({}, gptSlot);
+ // No customGptSlotMatching; winningBidsArray is empty in beforeEach
+ const wb = bidViewability.getMatchingWinningBidForGPTSlot(gptSlot);
expect(wb).to.equal(null);
});
});
- describe('fireViewabilityPixels', function() {
- let sandbox;
- let triggerPixelSpy;
-
- beforeEach(function() {
- sandbox = sinon.createSandbox();
- triggerPixelSpy = sandbox.spy(utils, ['triggerPixel']);
- });
-
- afterEach(function() {
- sandbox.restore();
- });
-
- it('DO NOT fire pixels if NOT mentioned in module config', function() {
- const moduleConfig = {};
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- expect(triggerPixelSpy.callCount).to.equal(0);
- });
-
- it('fire pixels if mentioned in module config', function() {
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0]).to.equal(url);
- });
- });
-
- it('USP: should include the us_privacy key when USP Consent is available', function () {
- const uspDataHandlerStub = sinon.stub(uspDataHandler, 'getConsentData');
- uspDataHandlerStub.returns('1YYY');
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0].indexOf(url)).to.equal(0);
- const testurl = parse(call.args[0]);
- const queryObject = utils.parseQS(testurl.query);
- expect(queryObject.us_privacy).to.equal('1YYY');
- });
- uspDataHandlerStub.restore();
- });
-
- it('USP: should not include the us_privacy key when USP Consent is not available', function () {
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0].indexOf(url)).to.equal(0);
- const testurl = parse(call.args[0]);
- const queryObject = utils.parseQS(testurl.query);
- expect(queryObject.us_privacy).to.equal(undefined);
- });
- });
-
- it('GDPR: should include the GDPR keys when GDPR Consent is available', function() {
- const gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData');
- gdprDataHandlerStub.returns({
- gdprApplies: true,
- consentString: 'consent',
- addtlConsent: 'moreConsent'
- });
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0].indexOf(url)).to.equal(0);
- const testurl = parse(call.args[0]);
- const queryObject = utils.parseQS(testurl.query);
- expect(queryObject.gdpr).to.equal('1');
- expect(queryObject.gdpr_consent).to.equal('consent');
- expect(queryObject.addtl_consent).to.equal('moreConsent');
- });
- gdprDataHandlerStub.restore();
- });
-
- it('GDPR: should not include the GDPR keys when GDPR Consent is not available', function () {
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0].indexOf(url)).to.equal(0);
- const testurl = parse(call.args[0]);
- const queryObject = utils.parseQS(testurl.query);
- expect(queryObject.gdpr).to.equal(undefined);
- expect(queryObject.gdpr_consent).to.equal(undefined);
- expect(queryObject.addtl_consent).to.equal(undefined);
- });
- });
-
- it('GDPR: should only include the GDPR keys for GDPR Consent fields with values', function () {
- const gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData');
- gdprDataHandlerStub.returns({
- gdprApplies: true,
- consentString: 'consent'
- });
- const moduleConfig = { firePixels: true };
- bidViewability.fireViewabilityPixels(moduleConfig, PBJS_WINNING_BID);
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
- const call = triggerPixelSpy.getCall(i);
- expect(call.args[0].indexOf(url)).to.equal(0);
- const testurl = parse(call.args[0]);
- const queryObject = utils.parseQS(testurl.query);
- expect(queryObject.gdpr).to.equal('1');
- expect(queryObject.gdpr_consent).to.equal('consent');
- expect(queryObject.addtl_consent).to.equal(undefined);
- });
- gdprDataHandlerStub.restore();
- })
- });
-
describe('impressionViewableHandler', function() {
let sandbox;
let triggerPixelSpy;
@@ -288,7 +160,7 @@ describe('#bidViewability', function() {
winningBidsArray.push(PBJS_WINNING_BID);
bidViewability.impressionViewableHandler(moduleConfig, EVENT_OBJ);
// fire pixels should be called
- PBJS_WINNING_BID.vurls.forEach((url, i) => {
+ VIEWABILITY_PIXEL_URLS.forEach((url, i) => {
const call = triggerPixelSpy.getCall(i);
expect(call.args[0]).to.equal(url);
});
diff --git a/test/spec/modules/categoryTranslation_spec.js b/test/spec/modules/categoryTranslation_spec.js
deleted file mode 100644
index 6c3bc41c037..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 d9742de3a5c..99acf6ec971 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/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js
index 3ba309f029f..54150aab322 100644
--- a/test/spec/modules/concertBidAdapter_spec.js
+++ b/test/spec/modules/concertBidAdapter_spec.js
@@ -3,6 +3,7 @@ import sinon from 'sinon';
import { spec, storage } from 'modules/concertBidAdapter.js';
import { hook } from 'src/hook.js';
import { getGlobal } from '../../../src/prebidGlobal.js';
+import * as adUnits from 'src/utils/adUnits';
describe('ConcertAdapter', function () {
let bidRequests;
@@ -86,7 +87,7 @@ describe('ConcertAdapter', function () {
}
sandbox = sinon.createSandbox();
- sandbox.stub(document, 'getElementById').withArgs('desktop_leaderboard_variable').returns(element)
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element)
});
afterEach(function () {
diff --git a/test/spec/modules/connatixBidAdapter_spec.js b/test/spec/modules/connatixBidAdapter_spec.js
index 3f960825cd4..82479617769 100644
--- a/test/spec/modules/connatixBidAdapter_spec.js
+++ b/test/spec/modules/connatixBidAdapter_spec.js
@@ -17,6 +17,7 @@ import * as utils from '../../../src/utils.js';
import * as ajax from '../../../src/ajax.js';
import { ADPOD, BANNER, VIDEO } from '../../../src/mediaTypes.js';
import * as winDimensions from '../../../src/utils/winDimensions.js';
+import * as adUnits from 'src/utils/adUnits';
const BIDDER_CODE = 'connatix';
@@ -88,7 +89,7 @@ describe('connatixBidAdapter', function () {
let getBoundingClientRectStub;
let topWinMock;
let querySelectorStub;
- let getElementByIdStub;
+ let getElementStub;
let sandbox;
beforeEach(() => {
@@ -105,7 +106,7 @@ describe('connatixBidAdapter', function () {
};
querySelectorStub = sandbox.stub(window.top.document, 'querySelector');
- getElementByIdStub = sandbox.stub(document, 'getElementById');
+ getElementStub = sandbox.stub(adUnits, 'getAdUnitElement');
sandbox.stub(winDimensions, 'getWinDimensions').callsFake(() => (
{
document: {
@@ -143,7 +144,7 @@ describe('connatixBidAdapter', function () {
});
querySelectorStub.withArgs('#validElement').returns(element);
- getElementByIdStub.returns(null);
+ getElementStub.returns(null);
const result = connatixDetectViewability(bid);
@@ -171,6 +172,7 @@ describe('connatixBidAdapter', function () {
height: 250
});
+ const getElementByIdStub = sandbox.stub(document, 'getElementById');
getElementByIdStub.withArgs('validElement').returns(element);
const result = connatixDetectViewability(bid);
@@ -201,7 +203,7 @@ describe('connatixBidAdapter', function () {
});
querySelectorStub.withArgs('#invalidElement').returns(null);
- getElementByIdStub.withArgs('adUnitCode123').returns(element);
+ getElementStub.returns(element);
const result = connatixDetectViewability(bid);
@@ -231,7 +233,7 @@ describe('connatixBidAdapter', function () {
});
// The fallback should use the adUnitCode to find the element
- getElementByIdStub.withArgs('adUnitCode123').returns(element);
+ getElementStub.returns(element);
const result = connatixDetectViewability(bid);
diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js
index 3d04b0f833c..a4c2a02f0b2 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/cwireBidAdapter_spec.js b/test/spec/modules/cwireBidAdapter_spec.js
index 1a514d33155..6943618cf51 100644
--- a/test/spec/modules/cwireBidAdapter_spec.js
+++ b/test/spec/modules/cwireBidAdapter_spec.js
@@ -6,6 +6,7 @@ import * as utils from "src/utils.js";
import sinon, { stub } from "sinon";
import { config } from "../../../src/config.js";
import * as autoplayLib from "../../../libraries/autoplayDetection/autoplay.js";
+import * as adUnits from 'src/utils/adUnits';
describe("C-WIRE bid adapter", () => {
config.setConfig({ debug: true });
@@ -101,8 +102,8 @@ describe("C-WIRE bid adapter", () => {
describe("buildRequests reads adUnit offsetWidth and offsetHeight", function () {
beforeEach(function () {
- const documentStub = sandbox.stub(document, "getElementById");
- documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({
+ const documentStub = sandbox.stub(adUnits, "getAdUnitElement");
+ documentStub.returns({
offsetWidth: 200,
offsetHeight: 250,
getBoundingClientRect() {
@@ -115,11 +116,9 @@ describe("C-WIRE bid adapter", () => {
const request = spec.buildRequests([bidRequest], bidderRequest);
const payload = JSON.parse(request.data);
- const el = document.getElementById(`${bidRequest.adUnitCode}`);
logInfo(JSON.stringify(payload));
- expect(el).to.exist;
expect(payload.slots[0].cwExt.dimensions.width).to.equal(200);
expect(payload.slots[0].cwExt.dimensions.height).to.equal(250);
expect(payload.slots[0].cwExt.style.maxHeight).to.not.exist;
@@ -131,8 +130,8 @@ describe("C-WIRE bid adapter", () => {
});
describe("buildRequests reads style attributes", function () {
beforeEach(function () {
- const documentStub = sandbox.stub(document, "getElementById");
- documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({
+ const documentStub = sandbox.stub(adUnits, "getAdUnitElement");
+ documentStub.returns({
style: {
maxWidth: "400px",
maxHeight: "350px",
@@ -147,11 +146,8 @@ describe("C-WIRE bid adapter", () => {
const request = spec.buildRequests([bidRequest], bidderRequest);
const payload = JSON.parse(request.data);
- const el = document.getElementById(`${bidRequest.adUnitCode}`);
-
logInfo(JSON.stringify(payload));
- expect(el).to.exist;
expect(payload.slots[0].cwExt.style.maxWidth).to.eq("400px");
expect(payload.slots[0].cwExt.style.maxHeight).to.eq("350px");
});
diff --git a/test/spec/modules/debugging_mod_spec.js b/test/spec/modules/debugging_mod_spec.js
index 39737272bed..ee8089b7a10 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/dmdIdSystem_spec.js b/test/spec/modules/dmdIdSystem_spec.js
deleted file mode 100644
index c85ec522440..00000000000
--- a/test/spec/modules/dmdIdSystem_spec.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import * as utils from '../../../src/utils.js';
-import { server } from 'test/mocks/xhr.js';
-import { dmdIdSubmodule } from 'modules/dmdIdSystem.js';
-
-describe('Dmd ID System', function () {
- let logErrorStub;
- const config = {
- params: {
- api_key: '33344ffjddk22k22k222k22234k',
- api_url: 'https://aix.hcn.health/api/v1/auths'
- }
- };
-
- beforeEach(function () {
- if (utils.logError.restore && utils.logError.restore.sinon) {
- utils.logError.restore();
- }
- logErrorStub = sinon.stub(utils, 'logError');
- });
-
- afterEach(function () {
- if (logErrorStub && logErrorStub.restore) {
- logErrorStub.restore();
- }
- });
-
- it('should log an error if no configParams were passed into getId', function () {
- dmdIdSubmodule.getId();
- expect(logErrorStub.calledOnce).to.be.true;
- });
-
- it('should log an error if configParams doesnot have api_key passed to getId', function () {
- dmdIdSubmodule.getId({ params: {} });
- expect(logErrorStub.calledOnce).to.be.true;
- });
-
- it('should log an error if configParams has invalid api_key passed into getId', function () {
- dmdIdSubmodule.getId({ params: { api_key: 123 } });
- expect(logErrorStub.calledOnce).to.be.true;
- });
-
- it('should not log an error if configParams has valid api_key passed into getId', function () {
- dmdIdSubmodule.getId({ params: { api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c' } });
- expect(logErrorStub.calledOnce).to.be.false;
- });
-
- it('should return undefined if empty value passed into decode', function () {
- expect(dmdIdSubmodule.decode()).to.be.undefined;
- });
-
- it('should return undefined if invalid dmd-dgid passed into decode', function () {
- expect(dmdIdSubmodule.decode(123)).to.be.undefined;
- });
-
- it('should return dmdId if valid dmd-dgid passed into decode', function () {
- const data = { 'dmdId': 'U12345' };
- expect(dmdIdSubmodule.decode('U12345')).to.deep.equal(data);
- });
-
- it('should return cacheObj if cacheObj is passed into getId', function () {
- const data = { 'dmdId': 'U12345' };
- expect(dmdIdSubmodule.getId(config, {}, { cookie: 'dmd-dgid' })).to.deep.equal({ cookie: 'dmd-dgid' });
- expect(server.requests.length).to.eq(0);
- });
-
- it('Should invoke callback with response from API call', function () {
- const callbackSpy = sinon.spy();
- const domain = utils.getWindowLocation().href;
- const callback = dmdIdSubmodule.getId(config).callback;
- callback(callbackSpy);
- const request = server.requests[0];
- expect(request.method).to.eq('GET');
- expect(request.requestHeaders['x-domain']).to.be.eq(domain);
- expect(request.url).to.eq(config.params.api_url);
- request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ dgid: 'U12345' }));
- expect(callbackSpy.lastCall.lastArg).to.deep.equal('U12345');
- });
-
- it('Should log error if API response is not valid', function () {
- const callbackSpy = sinon.spy();
- const domain = utils.getWindowLocation().href;
- const callback = dmdIdSubmodule.getId(config).callback;
- callback(callbackSpy);
- const request = server.requests[0];
- expect(request.method).to.eq('GET');
- expect(request.requestHeaders['x-domain']).to.be.eq(domain);
- expect(request.url).to.eq(config.params.api_url);
- request.respond(400, { 'Content-Type': 'application/json' }, undefined);
- expect(logErrorStub.calledOnce).to.be.true;
- });
-
- it('Should log error if API call throws error', function () {
- const callbackSpy = sinon.spy();
- const callback = dmdIdSubmodule.getId(config).callback;
- callback(callbackSpy);
- const request = server.requests[0];
- expect(request.url).to.eq(config.params.api_url);
- request.error();
- expect(logErrorStub.calledOnce).to.be.true;
- });
-});
diff --git a/test/spec/modules/freeWheelAdserverVideo_spec.js b/test/spec/modules/freeWheelAdserverVideo_spec.js
deleted file mode 100644
index 0c65bbefc7e..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 bd32a23c956..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/gptPreAuction_spec.js b/test/spec/modules/gptPreAuction_spec.js
index e9063b746aa..78e169aa970 100644
--- a/test/spec/modules/gptPreAuction_spec.js
+++ b/test/spec/modules/gptPreAuction_spec.js
@@ -183,9 +183,8 @@ describe('GPT pre-auction module', () => {
it('should use the customGptSlotMatching function if one is given', () => {
config.setConfig({
- gptPreAuction: {
- customGptSlotMatching: slot =>
- adUnitCode => adUnitCode.toUpperCase() === slot.getAdUnitPath().toUpperCase()
+ customGptSlotMatching: slot => {
+ return (adUnitCode) => adUnitCode.toUpperCase() === slot.getAdUnitPath().toUpperCase();
}
});
@@ -194,6 +193,7 @@ describe('GPT pre-auction module', () => {
appendGptSlots([adUnit]);
expect(adUnit.ortb2Imp.ext.data.adserver).to.be.an('object');
expect(adUnit.ortb2Imp.ext.data.adserver).to.deep.equal({ name: 'gam', adslot: 'slotCode1' });
+ config.resetConfig();
});
});
@@ -208,27 +208,14 @@ describe('GPT pre-auction module', () => {
expect(_currentConfig).to.be.an('object').that.is.empty;
});
- it('should accept custom functions in config', () => {
- config.setConfig({
- gptPreAuction: {
- customGptSlotMatching: () => 'customGptSlot',
- }
- });
-
- expect(_currentConfig.enabled).to.equal(true);
- expect(_currentConfig.customGptSlotMatching).to.a('function');
- expect(_currentConfig.customGptSlotMatching()).to.equal('customGptSlot');
- });
-
it('should check that custom functions in config are type function', () => {
config.setConfig({
gptPreAuction: {
- customGptSlotMatching: 12345,
+ customPreAuction: 12345,
}
});
expect(_currentConfig).to.deep.equal({
enabled: true,
- customGptSlotMatching: false,
customPreAuction: false,
useDefaultPreAuction: true
});
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 db043a88238..9a509542d8e 100644
--- a/test/spec/modules/gumgumBidAdapter_spec.js
+++ b/test/spec/modules/gumgumBidAdapter_spec.js
@@ -100,39 +100,6 @@ describe('gumgumAdapter', function () {
describe('buildRequests', function () {
const sizesArray = [[300, 250], [300, 600]];
- const id5Eid = {
- source: 'id5-sync.com',
- uids: [{
- id: 'uid-string',
- ext: {
- linkType: 2
- }
- }]
- };
- const pubProvidedIdEids = [
- {
- uids: [
- {
- ext: {
- stype: 'ppuid',
- },
- id: 'aac4504f-ef89-401b-a891-ada59db44336',
- },
- ],
- source: 'audigent.com',
- },
- {
- uids: [
- {
- ext: {
- stype: 'ppuid',
- },
- id: 'y-zqTHmW9E2uG3jEETC6i6BjGcMhPXld2F~A',
- },
- ],
- source: 'crwdcntrl.net',
- },
- ];
const bidderRequest = {
ortb2: {
site: {
@@ -169,7 +136,38 @@ describe('gumgumAdapter', function () {
sizes: sizesArray
}
},
- userIdAsEids: [id5Eid, ...pubProvidedIdEids],
+ userId: {
+ id5id: {
+ uid: 'uid-string',
+ ext: {
+ linkType: 2
+ }
+ }
+ },
+ pubProvidedId: [
+ {
+ uids: [
+ {
+ ext: {
+ stype: 'ppuid',
+ },
+ id: 'aac4504f-ef89-401b-a891-ada59db44336',
+ },
+ ],
+ source: 'sonobi.com',
+ },
+ {
+ uids: [
+ {
+ ext: {
+ stype: 'ppuid',
+ },
+ id: 'y-zqTHmW9E2uG3jEETC6i6BjGcMhPXld2F~A',
+ },
+ ],
+ source: 'aol.com',
+ },
+ ],
adUnitCode: 'adunit-code',
sizes: sizesArray,
bidId: '30b31c1838de1e',
@@ -229,139 +227,13 @@ describe('gumgumAdapter', function () {
it('should set pubProvidedId if the uid and pubProvidedId are available', function () {
const request = { ...bidRequests[0] };
const bidRequest = spec.buildRequests([request])[0];
- expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(pubProvidedIdEids));
- });
- it('should filter pubProvidedId entries by allowed sources', function () {
- const filteredRequest = {
- ...bidRequests[0],
- userIdAsEids: [
- {
- source: 'audigent.com',
- uids: [{ id: 'ppid-1', ext: { stype: 'ppuid' } }]
- },
- {
- source: 'sonobi.com',
- uids: [{ id: 'ppid-2', ext: { stype: 'ppuid' } }]
- }
- ]
- };
- const bidRequest = spec.buildRequests([filteredRequest])[0];
- const pubProvidedIds = JSON.parse(bidRequest.data.pubProvidedId);
- expect(pubProvidedIds.length).to.equal(1);
- expect(pubProvidedIds[0].source).to.equal('audigent.com');
- });
- it('should not set pubProvidedId when all sources are filtered out', function () {
- const filteredRequest = {
- ...bidRequests[0],
- userIdAsEids: [{
- source: 'sonobi.com',
- uids: [{ id: 'ppid-2', ext: { stype: 'ppuid' } }]
- }]
- };
- const bidRequest = spec.buildRequests([filteredRequest])[0];
- expect(bidRequest.data.pubProvidedId).to.equal(undefined);
+ expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(bidRequests[0].userId.pubProvidedId));
});
it('should set id5Id and id5IdLinkType if the uid and linkType are available', function () {
const request = { ...bidRequests[0] };
const bidRequest = spec.buildRequests([request])[0];
- expect(bidRequest.data.id5Id).to.equal(id5Eid.uids[0].id);
- expect(bidRequest.data.id5IdLinkType).to.equal(id5Eid.uids[0].ext.linkType);
- });
- it('should use bidderRequest.ortb2.user.ext.eids when bid-level eids are not available', function () {
- const request = { ...bidRequests[0], userIdAsEids: undefined };
- const fakeBidderRequest = {
- ...bidderRequest,
- ortb2: {
- ...bidderRequest.ortb2,
- user: {
- ext: {
- eids: [{
- source: 'liveramp.com',
- uids: [{
- id: 'fallback-idl-env'
- }]
- }]
- }
- }
- }
- };
- const bidRequest = spec.buildRequests([request], fakeBidderRequest)[0];
- expect(bidRequest.data.idl_env).to.equal('fallback-idl-env');
- });
- it('should prioritize bidderRequest.ortb2.user.ext.eids over bid-level eids', function () {
- const request = {
- ...bidRequests[0],
- userIdAsEids: [{
- source: 'liveramp.com',
- uids: [{ id: 'bid-level-idl-env' }]
- }]
- };
- const fakeBidderRequest = {
- ...bidderRequest,
- ortb2: {
- ...bidderRequest.ortb2,
- user: {
- ext: {
- eids: [{
- source: 'liveramp.com',
- uids: [{ id: 'ortb2-level-idl-env' }]
- }]
- }
- }
- }
- };
- const bidRequest = spec.buildRequests([request], fakeBidderRequest)[0];
- expect(bidRequest.data.idl_env).to.equal('ortb2-level-idl-env');
- });
- it('should keep identity output consistent for prebid10 ortb2 eids input', function () {
- const request = { ...bidRequests[0], userIdAsEids: undefined };
- const fakeBidderRequest = {
- ...bidderRequest,
- ortb2: {
- ...bidderRequest.ortb2,
- user: {
- ext: {
- eids: [
- {
- source: 'uidapi.com',
- uids: [{ id: 'uid2-token', atype: 3 }]
- },
- {
- source: 'liveramp.com',
- uids: [{ id: 'idl-envelope', atype: 1 }]
- },
- {
- source: 'adserver.org',
- uids: [{ id: 'tdid-value', atype: 1, ext: { rtiPartner: 'TDID' } }]
- },
- {
- source: 'id5-sync.com',
- uids: [{ id: 'id5-value', atype: 1, ext: { linkType: 2 } }]
- },
- {
- source: 'audigent.com',
- uids: [{ id: 'ppid-1', atype: 1, ext: { stype: 'ppuid' } }]
- },
- {
- source: 'sonobi.com',
- uids: [{ id: 'ppid-2', atype: 1, ext: { stype: 'ppuid' } }]
- }
- ]
- }
- }
- }
- };
- const bidRequest = spec.buildRequests([request], fakeBidderRequest)[0];
-
- // Expected identity payload shape from legacy GumGum request fields.
- expect(bidRequest.data.uid2).to.equal('uid2-token');
- expect(bidRequest.data.idl_env).to.equal('idl-envelope');
- expect(bidRequest.data.tdid).to.equal('tdid-value');
- expect(bidRequest.data.id5Id).to.equal('id5-value');
- expect(bidRequest.data.id5IdLinkType).to.equal(2);
- const pubProvidedId = JSON.parse(bidRequest.data.pubProvidedId);
- expect(pubProvidedId.length).to.equal(1);
- expect(pubProvidedId[0].source).to.equal('audigent.com');
+ expect(bidRequest.data.id5Id).to.equal(bidRequests[0].userId.id5id.uid);
+ expect(bidRequest.data.id5IdLinkType).to.equal(bidRequests[0].userId.id5id.ext.linkType);
});
it('should set pubId param if found', function () {
@@ -426,266 +298,6 @@ describe('gumgumAdapter', function () {
const bidRequest = spec.buildRequests([request], bidderRequest)[0];
expect(bidRequest.data).to.have.property('curl', 'http://pub.com/news');
});
-
- describe('content metadata extraction', function() {
- it('should extract all site.content fields', function() {
- const ortb2WithContent = {
- site: {
- content: {
- id: 'content-id-123',
- episode: 5,
- title: 'Test Episode Title',
- series: 'Test Series',
- season: 'Season 2',
- genre: 'Comedy',
- contentrating: 'PG-13',
- userrating: '4.5',
- context: 1,
- livestream: 1,
- len: 1800,
- language: 'en',
- url: 'https://example.com/content',
- cattax: 6,
- prodq: 2,
- qagmediarating: 1,
- keywords: 'keyword1,keyword2,keyword3',
- cat: ['IAB1-1', 'IAB1-2', 'IAB1-3'],
- producer: {
- id: 'producer-123',
- name: 'Test Producer'
- },
- channel: {
- id: 'channel-123',
- name: 'Test Channel',
- domain: 'testchannel.com'
- },
- network: {
- name: 'Test Network'
- }
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ...bidderRequest, ortb2: ortb2WithContent })[0];
-
- expect(bidRequest.data.itype).to.equal('site');
- expect(bidRequest.data.cid).to.equal('content-id-123');
- expect(bidRequest.data.cepisode).to.equal(5);
- expect(bidRequest.data.ctitle).to.equal('Test Episode Title');
- expect(bidRequest.data.cseries).to.equal('Test Series');
- expect(bidRequest.data.cseason).to.equal('Season 2');
- expect(bidRequest.data.cgenre).to.equal('Comedy');
- expect(bidRequest.data.crating).to.equal('PG-13');
- expect(bidRequest.data.cur).to.equal('4.5');
- expect(bidRequest.data.cctx).to.equal(1);
- expect(bidRequest.data.clive).to.equal(1);
- expect(bidRequest.data.clen).to.equal(1800);
- expect(bidRequest.data.clang).to.equal('en');
- expect(bidRequest.data.curl).to.equal('https://example.com/content');
- expect(bidRequest.data.cattax).to.equal(6);
- expect(bidRequest.data.cprodq).to.equal(2);
- expect(bidRequest.data.cqag).to.equal(1);
- expect(bidRequest.data.ckw).to.equal('keyword1,keyword2,keyword3');
- expect(bidRequest.data.ccat).to.equal('IAB1-1,IAB1-2,IAB1-3');
- expect(bidRequest.data.cpid).to.equal('producer-123');
- expect(bidRequest.data.cpname).to.equal('Test Producer');
- expect(bidRequest.data.cchannelid).to.equal('channel-123');
- expect(bidRequest.data.cchannel).to.equal('Test Channel');
- expect(bidRequest.data.cchanneldomain).to.equal('testchannel.com');
- expect(bidRequest.data.cnetwork).to.equal('Test Network');
- });
-
- it('should extract app.content fields when site.content is not present', function() {
- const ortb2WithAppContent = {
- app: {
- content: {
- id: 'app-content-id',
- title: 'App Content Title',
- series: 'App Series',
- url: 'https://example.com/app-content'
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2: ortb2WithAppContent })[0];
-
- expect(bidRequest.data.itype).to.equal('app');
- expect(bidRequest.data.cid).to.equal('app-content-id');
- expect(bidRequest.data.ctitle).to.equal('App Content Title');
- expect(bidRequest.data.cseries).to.equal('App Series');
- expect(bidRequest.data.curl).to.equal('https://example.com/app-content');
- });
-
- it('should prioritize site.content over app.content', function() {
- const ortb2WithBoth = {
- site: {
- content: {
- id: 'site-content-id',
- title: 'Site Content'
- }
- },
- app: {
- content: {
- id: 'app-content-id',
- title: 'App Content'
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2: ortb2WithBoth })[0];
-
- expect(bidRequest.data.itype).to.equal('site');
- expect(bidRequest.data.cid).to.equal('site-content-id');
- expect(bidRequest.data.ctitle).to.equal('Site Content');
- });
-
- it('should handle keywords as an array', function() {
- const ortb2 = {
- site: {
- content: {
- keywords: ['keyword1', 'keyword2', 'keyword3']
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.ckw).to.equal('keyword1,keyword2,keyword3');
- });
-
- it('should handle keywords as a string', function() {
- const ortb2 = {
- site: {
- content: {
- keywords: 'keyword1,keyword2,keyword3'
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.ckw).to.equal('keyword1,keyword2,keyword3');
- });
-
- it('should not include content params when content object is missing', function() {
- const ortb2 = {
- site: {
- page: 'https://example.com'
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data).to.not.have.property('cid');
- expect(bidRequest.data).to.not.have.property('ctitle');
- expect(bidRequest.data).to.not.have.property('curl');
- });
-
- it('should not include undefined or null content fields', function() {
- const ortb2 = {
- site: {
- content: {
- id: 'content-123',
- title: undefined,
- series: null,
- season: ''
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.cid).to.equal('content-123');
- expect(bidRequest.data).to.not.have.property('ctitle');
- expect(bidRequest.data).to.not.have.property('cseries');
- expect(bidRequest.data).to.not.have.property('cseason');
- });
-
- it('should handle zero values for numeric fields', function() {
- const ortb2 = {
- site: {
- content: {
- episode: 0,
- context: 0,
- livestream: 0,
- len: 0,
- cattax: 0,
- prodq: 0,
- qagmediarating: 0
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.cepisode).to.equal(0);
- expect(bidRequest.data.cctx).to.equal(0);
- expect(bidRequest.data.clive).to.equal(0);
- expect(bidRequest.data.clen).to.equal(0);
- expect(bidRequest.data.cattax).to.equal(0);
- expect(bidRequest.data.cprodq).to.equal(0);
- expect(bidRequest.data.cqag).to.equal(0);
- });
-
- it('should handle empty arrays for cat', function() {
- const ortb2 = {
- site: {
- content: {
- cat: []
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data).to.not.have.property('ccat');
- });
-
- it('should handle partial producer data', function() {
- const ortb2 = {
- site: {
- content: {
- producer: {
- id: 'producer-id-only'
- }
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.cpid).to.equal('producer-id-only');
- expect(bidRequest.data).to.not.have.property('cpname');
- });
-
- it('should handle episode as string', function() {
- const ortb2 = {
- site: {
- content: {
- episode: 'S01E05'
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ortb2 })[0];
-
- expect(bidRequest.data.cepisode).to.equal('S01E05');
- });
-
- it('should not override existing curl from irisid extraction', function() {
- const ortb2 = {
- site: {
- content: {
- url: 'https://content-url.com'
- }
- }
- };
- const request = { ...bidRequests[0] };
- const bidRequest = spec.buildRequests([request], { ...bidderRequest, ortb2 })[0];
-
- expect(bidRequest.data.curl).to.equal('https://content-url.com');
- });
- });
it('should not set the iriscat param when not found', function () {
const request = { ...bidRequests[0] }
const bidRequest = spec.buildRequests([request])[0];
@@ -722,26 +334,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 } } }
@@ -1006,7 +598,7 @@ describe('gumgumAdapter', function () {
it('should set pubProvidedId if the uid and pubProvidedId are available', function () {
const request = { ...bidRequests[0] };
const bidRequest = spec.buildRequests([request])[0];
- expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(pubProvidedIdEids));
+ expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(bidRequests[0].userId.pubProvidedId));
});
it('should add gdpr consent parameters if gdprConsent is present', function () {
@@ -1106,40 +698,14 @@ describe('gumgumAdapter', function () {
expect(bidRequest.data.uspConsent).to.eq(uspConsentObj.uspConsent);
});
it('should add a tdid parameter if request contains unified id from TradeDesk', function () {
- const tdidEid = {
- source: 'adserver.org',
- uids: [{
- id: 'tradedesk-id',
- ext: {
- rtiPartner: 'TDID'
- }
- }]
- };
- const request = Object.assign({}, bidRequests[0], { userIdAsEids: [...bidRequests[0].userIdAsEids, tdidEid] });
- const bidRequest = spec.buildRequests([request])[0];
- expect(bidRequest.data.tdid).to.eq(tdidEid.uids[0].id);
- });
- it('should add a tdid parameter when TDID uid is not the first uid in adserver.org', function () {
- const tdidEid = {
- source: 'adserver.org',
- uids: [
- {
- id: 'non-tdid-first',
- ext: {
- rtiPartner: 'NOT_TDID'
- }
- },
- {
- id: 'tradedesk-id',
- ext: {
- rtiPartner: 'TDID'
- }
- }
- ]
- };
- const request = Object.assign({}, bidRequests[0], { userIdAsEids: [tdidEid] });
+ const unifiedId = {
+ 'userId': {
+ 'tdid': 'tradedesk-id'
+ }
+ }
+ const request = Object.assign(unifiedId, bidRequests[0]);
const bidRequest = spec.buildRequests([request])[0];
- expect(bidRequest.data.tdid).to.eq('tradedesk-id');
+ expect(bidRequest.data.tdid).to.eq(unifiedId.userId.tdid);
});
it('should not add a tdid parameter if unified id is not found', function () {
const request = spec.buildRequests(bidRequests)[0];
@@ -1147,8 +713,7 @@ describe('gumgumAdapter', function () {
});
it('should send IDL envelope ID if available', function () {
const idl_env = 'abc123';
- const idlEid = { source: 'liveramp.com', uids: [{ id: idl_env }] };
- const request = { ...bidRequests[0], userIdAsEids: [idlEid] };
+ const request = { ...bidRequests[0], userId: { idl_env } };
const bidRequest = spec.buildRequests([request])[0];
expect(bidRequest.data).to.have.property('idl_env');
@@ -1162,8 +727,7 @@ describe('gumgumAdapter', function () {
});
it('should add a uid2 parameter if request contains uid2 id', function () {
const uid2 = { id: 'sample-uid2' };
- const uid2Eid = { source: 'uidapi.com', uids: [{ id: uid2.id }] };
- const request = { ...bidRequests[0], userIdAsEids: [uid2Eid] };
+ const request = { ...bidRequests[0], userId: { uid2 } };
const bidRequest = spec.buildRequests([request])[0];
expect(bidRequest.data).to.have.property('uid2');
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/intersectionRtdProvider_spec.js b/test/spec/modules/intersectionRtdProvider_spec.js
deleted file mode 100644
index 9fa934fd4f3..00000000000
--- a/test/spec/modules/intersectionRtdProvider_spec.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import { config as _config, config } from 'src/config.js';
-import { expect } from 'chai';
-import * as events from 'src/events.js';
-import * as prebidGlobal from 'src/prebidGlobal.js';
-import { intersectionSubmodule } from 'modules/intersectionRtdProvider.js';
-import * as utils from 'src/utils.js';
-import { getGlobal } from 'src/prebidGlobal.js';
-import 'src/prebid.js';
-
-describe('Intersection RTD Provider', function () {
- let sandbox;
- let placeholder;
- const pbjs = getGlobal();
- const adUnit = {
- code: 'ad-slot-1',
- mediaTypes: {
- banner: {
- sizes: [[300, 250]]
- }
- },
- bids: [
- {
- bidder: 'fake'
- }
- ]
- };
- const providerConfig = { name: 'intersection', waitForIt: true };
- const rtdConfig = { realTimeData: { auctionDelay: 200, dataProviders: [providerConfig] } }
- describe('IntersectionObserver not supported', function() {
- beforeEach(function() {
- sandbox = sinon.createSandbox();
- });
- afterEach(function() {
- sandbox.restore();
- sandbox = undefined;
- });
- it('init should return false', function () {
- sandbox.stub(window, 'IntersectionObserver').value(undefined);
- expect(intersectionSubmodule.init({})).is.false;
- });
- });
- describe('IntersectionObserver supported', function() {
- beforeEach(function() {
- sandbox = sinon.createSandbox();
- placeholder = createDiv();
- append();
- const __config = {};
- sandbox.stub(_config, 'getConfig').callsFake(function (path) {
- return utils.deepAccess(__config, path);
- });
- sandbox.stub(_config, 'setConfig').callsFake(function (obj) {
- utils.mergeDeep(__config, obj);
- });
- sandbox.stub(window, 'IntersectionObserver').callsFake(function (cb) {
- return {
- observe(el) {
- cb([
- {
- target: el,
- intersectionRatio: 1,
- isIntersecting: true,
- time: Date.now(),
- boundingClientRect: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0, x: 0, y: 0 },
- intersectionRect: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0, x: 0, y: 0 },
- rootRect: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0, x: 0, y: 0 }
- }
- ]);
- },
- unobserve() {},
- disconnect() {}
- };
- });
- });
- afterEach(function() {
- sandbox.restore();
- remove();
- sandbox = undefined;
- placeholder = undefined;
- pbjs.removeAdUnit();
- });
- it('init should return true', function () {
- expect(intersectionSubmodule.init({})).is.true;
- });
- it('should set intersection. (request with "adUnitCodes")', function(done) {
- pbjs.addAdUnits([utils.deepClone(adUnit)]);
- config.setConfig(rtdConfig);
- const onDone = sandbox.stub();
- const requestBidObject = { adUnitCodes: [adUnit.code] };
- intersectionSubmodule.init({});
- intersectionSubmodule.getBidRequestData(
- requestBidObject,
- onDone,
- providerConfig
- );
- setTimeout(function() {
- expect(pbjs.adUnits[0].bids[0]).to.have.property('intersection');
- done();
- }, 200);
- });
- it('should set intersection. (request with "adUnits")', function(done) {
- config.setConfig(rtdConfig);
- const onDone = sandbox.stub();
- const requestBidObject = { adUnits: [utils.deepClone(adUnit)] };
- intersectionSubmodule.init();
- intersectionSubmodule.getBidRequestData(
- requestBidObject,
- onDone,
- providerConfig
- );
- setTimeout(function() {
- expect(requestBidObject.adUnits[0].bids[0]).to.have.property('intersection');
- done();
- }, 200);
- });
- it('should set intersection. (request all)', function(done) {
- pbjs.addAdUnits([utils.deepClone(adUnit)]);
- config.setConfig(rtdConfig);
- const onDone = sandbox.stub();
- const requestBidObject = {};
- intersectionSubmodule.init({});
- intersectionSubmodule.getBidRequestData(
- requestBidObject,
- onDone,
- providerConfig
- );
- setTimeout(function() {
- expect(pbjs.adUnits[0].bids[0]).to.have.property('intersection');
- done();
- }, 200);
- });
- it('should call done due timeout', function(done) {
- config.setConfig(rtdConfig);
- remove();
- const onDone = sandbox.stub();
- const requestBidObject = { adUnits: [utils.deepClone(adUnit)] };
- intersectionSubmodule.init({});
- intersectionSubmodule.getBidRequestData(
- requestBidObject,
- onDone,
- { ...providerConfig, test: 1 }
- );
- setTimeout(function() {
- sinon.assert.calledOnce(onDone);
- expect(requestBidObject.adUnits[0].bids[0]).to.not.have.property('intersection');
- done();
- }, 300);
- });
- });
- function createDiv() {
- const div = document.createElement('div');
- div.id = adUnit.code;
- return div;
- }
- function append() {
- if (placeholder) {
- document.body.appendChild(placeholder);
- }
- }
- function remove() {
- if (placeholder && placeholder.parentElement) {
- placeholder.parentElement.removeChild(placeholder);
- }
- }
-});
diff --git a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js
index b4e6dd8629b..af29701aa22 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 d6a5d624547..837225f1844 100644
--- a/test/spec/modules/ixBidAdapter_spec.js
+++ b/test/spec/modules/ixBidAdapter_spec.js
@@ -2,7 +2,7 @@ import * as utils from 'src/utils.js';
import { config } from 'src/config.js';
import { expect } from 'chai';
import { newBidder } from 'src/adapters/bidderFactory.js';
-import { spec, storage, FEATURE_TOGGLES, LOCAL_STORAGE_FEATURE_TOGGLES_KEY, REQUESTED_FEATURE_TOGGLES, combineImps, bidToVideoImp, bidToNativeImp, deduplicateImpExtFields, removeSiteIDs, addDeviceInfo, getDivIdFromAdUnitCode } from '../../../modules/ixBidAdapter.js';
+import { spec, storage, FEATURE_TOGGLES, LOCAL_STORAGE_FEATURE_TOGGLES_KEY, REQUESTED_FEATURE_TOGGLES, combineImps, bidToVideoImp, bidToNativeImp, deduplicateImpExtFields, removeSiteIDs, addDeviceInfo, getDivIdFromAdUnit } from '../../../modules/ixBidAdapter.js';
import { deepAccess, deepClone } from '../../../src/utils.js';
import * as ajaxLib from 'src/ajax.js';
import * as gptUtils from '../../../libraries/gptUtils/gptUtils.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;
}
@@ -3638,78 +3590,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
@@ -4355,106 +4235,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;
@@ -4489,7 +4269,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);
@@ -5448,15 +5227,15 @@ describe('IndexexchangeAdapter', function () {
const el = document.createElement('div');
el.id = adUnitCode;
document.body.appendChild(el);
- expect(getDivIdFromAdUnitCode(adUnitCode)).to.equal(adUnitCode);
+ expect(getDivIdFromAdUnit(adUnitCode, { code: adUnitCode })).to.equal(adUnitCode);
document.body.removeChild(el);
});
it('retrieves divId from GPT once and caches result', () => {
const adUnitCode = 'div-ad2';
const stub = sinon.stub(gptUtils, 'getGptSlotInfoForAdUnitCode').returns({ divId: 'gpt-div' });
- const first = getDivIdFromAdUnitCode(adUnitCode);
- const second = getDivIdFromAdUnitCode(adUnitCode);
+ const first = getDivIdFromAdUnit(adUnitCode, {});
+ const second = getDivIdFromAdUnit(adUnitCode, {});
expect(first).to.equal('gpt-div');
expect(second).to.equal('gpt-div');
expect(stub.calledOnce).to.be.true;
diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js
index 8f6dc319c01..4de51a7b860 100644
--- a/test/spec/modules/kargoBidAdapter_spec.js
+++ b/test/spec/modules/kargoBidAdapter_spec.js
@@ -1932,55 +1932,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/livewrappedAnalyticsAdapter_spec.js b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js
index 2db52ba4cac..56b7df292b8 100644
--- a/test/spec/modules/livewrappedAnalyticsAdapter_spec.js
+++ b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js
@@ -3,6 +3,7 @@ import { AD_RENDER_FAILED_REASON, EVENTS, STATUS } from 'src/constants.js';
import { config } from 'src/config.js';
import { server } from 'test/mocks/xhr.js';
import { setConfig } from 'modules/currency.js';
+import * as adUnits from 'src/utils/adUnits';
const events = require('src/events');
const utils = require('src/utils');
@@ -323,7 +324,7 @@ describe('Livewrapped analytics adapter', function () {
}
sandbox.stub(events, 'getEvents').returns([]);
sandbox.stub(utils, 'timestamp').returns(1519149562416);
- sandbox.stub(document, 'getElementById').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
clock = sandbox.useFakeTimers(1519767013781);
setConfig({
diff --git a/test/spec/modules/logicadBidAdapter_spec.js b/test/spec/modules/logicadBidAdapter_spec.js
index 47351f68304..489cdf834da 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 5de70f83982..71087fbdcb3 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', () => {
@@ -174,12 +173,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 c67d6593696..aedf8a5c2d1 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 4dc07ecaa8b..86fd4275786 100644
--- a/test/spec/modules/marsmediaBidAdapter_spec.js
+++ b/test/spec/modules/marsmediaBidAdapter_spec.js
@@ -1,8 +1,8 @@
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';
+import * as adUnits from 'src/utils/adUnits';
var marsAdapter = spec;
@@ -73,7 +73,7 @@ describe('marsmedia adapter tests', function () {
];
sandbox = sinon.createSandbox();
- sandbox.stub(document, 'getElementById').withArgs('Unit-Code').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
sandbox.stub(utils, 'getWindowTop').returns(win);
sandbox.stub(utils, 'getWindowSelf').returns(win);
});
@@ -399,15 +399,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 887acb3fe8d..fae28156b08 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/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js
index 15c83e9a265..6368a1abfca 100644
--- a/test/spec/modules/medianetBidAdapter_spec.js
+++ b/test/spec/modules/medianetBidAdapter_spec.js
@@ -6,6 +6,7 @@ import { config } from '../../../src/config.js';
import { server } from '../../mocks/xhr.js';
import { resetWinDimensions } from '../../../src/utils.js';
import { getGlobal } from '../../../src/prebidGlobal.js';
+import * as adUnits from 'src/utils/adUnits';
getGlobal().version = getGlobal().version || 'version';
const VALID_BID_REQUEST = [{
@@ -1979,17 +1980,13 @@ describe('Media.net bid adapter', function () {
beforeEach(function () {
getGlobal().medianetGlobals = {};
- const documentStub = sandbox.stub(document, 'getElementById');
const boundingRect = {
top: 50,
left: 50,
bottom: 100,
right: 100
};
- documentStub.withArgs('div-gpt-ad-1460505748561-123').returns({
- getBoundingClientRect: () => boundingRect
- });
- documentStub.withArgs('div-gpt-ad-1460505748561-0').returns({
+ sandbox.stub(adUnits, 'getAdUnitElement').returns({
getBoundingClientRect: () => boundingRect
});
const windowSizeStub = sandbox.stub(spec, 'getWindowSize');
@@ -2066,19 +2063,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();
@@ -2102,14 +2086,14 @@ describe('Media.net bid adapter', function () {
});
describe('slot visibility', function () {
- let documentStub;
+ let elementStub;
beforeEach(function () {
const windowSizeStub = sandbox.stub(spec, 'getWindowSize');
windowSizeStub.returns({
w: 1000,
h: 1000
});
- documentStub = sandbox.stub(document, 'getElementById');
+ elementStub = sandbox.stub(adUnits, 'getAdUnitElement');
});
it('slot visibility should be 2 and ratio 0 when ad unit is BTF', function () {
const boundingRect = {
@@ -2118,10 +2102,7 @@ describe('Media.net bid adapter', function () {
bottom: 1050,
right: 1050
};
- documentStub.withArgs('div-gpt-ad-1460505748561-123').returns({
- getBoundingClientRect: () => boundingRect
- });
- documentStub.withArgs('div-gpt-ad-1460505748561-0').returns({
+ elementStub.returns({
getBoundingClientRect: () => boundingRect
});
@@ -2137,10 +2118,7 @@ describe('Media.net bid adapter', function () {
bottom: 1050,
right: 1050
};
- documentStub.withArgs('div-gpt-ad-1460505748561-123').returns({
- getBoundingClientRect: () => boundingRect
- });
- documentStub.withArgs('div-gpt-ad-1460505748561-0').returns({
+ elementStub.returns({
getBoundingClientRect: () => boundingRect
});
const bidReq = spec.buildRequests(VALID_BID_REQUEST, VALID_AUCTIONDATA);
@@ -2155,10 +2133,7 @@ describe('Media.net bid adapter', function () {
bottom: 1050,
right: 1050
};
- documentStub.withArgs('div-gpt-ad-1460505748561-123').returns({
- getBoundingClientRect: () => boundingRect
- });
- documentStub.withArgs('div-gpt-ad-1460505748561-0').returns({
+ elementStub.returns({
getBoundingClientRect: () => boundingRect
});
const bidReq = spec.buildRequests(VALID_BID_REQUEST, VALID_AUCTIONDATA);
@@ -2183,12 +2158,9 @@ describe('Media.net bid adapter', function () {
bottom: 1050,
right: 1050
};
- documentStub.withArgs(divId).returns({
+ elementStub.returns({
getBoundingClientRect: () => boundingRect
- });
- documentStub.withArgs('div-gpt-ad-1460505748561-123').returns({
- getBoundingClientRect: () => boundingRect
- });
+ })
const bidRequest = [{ ...VALID_BID_REQUEST[0], adUnitCode: code }]
const bidReq = spec.buildRequests(bidRequest, VALID_AUCTIONDATA);
@@ -2254,32 +2226,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 88c3c56ba03..d269a99d74d 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/msftBidAdapter_spec.js b/test/spec/modules/msftBidAdapter_spec.js
index 9f7d757d897..2f5f1014594 100644
--- a/test/spec/modules/msftBidAdapter_spec.js
+++ b/test/spec/modules/msftBidAdapter_spec.js
@@ -210,7 +210,6 @@ describe('msftBidAdapter', function () {
const bidderRequest = Object.assign({}, testBidderRequest, {
bids: bidRequests
});
- debugger;// eslint-disable-line no-debugger
const request = spec.buildRequests(bidRequests, bidderRequest)[0];
expect(request.method).to.equal('POST');
const data = request.data;
diff --git a/test/spec/modules/omsBidAdapter_spec.js b/test/spec/modules/omsBidAdapter_spec.js
index bdbcc617588..1ec6ed7c80b 100644
--- a/test/spec/modules/omsBidAdapter_spec.js
+++ b/test/spec/modules/omsBidAdapter_spec.js
@@ -3,6 +3,7 @@ import * as utils from 'src/utils.js';
import { spec } from 'modules/omsBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory.js';
import * as winDimensions from 'src/utils/winDimensions.js';
+import * as adUnits from 'src/utils/adUnits';
const URL = 'https://rt.marphezis.com/hb';
@@ -83,7 +84,7 @@ describe('omsBidAdapter', function () {
}];
sandbox = sinon.createSandbox();
- sandbox.stub(document, 'getElementById').withArgs('adunit-code').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
sandbox.stub(winDimensions, 'getWinDimensions').returns(win);
sandbox.stub(utils, 'getWindowTop').returns(win);
sandbox.stub(utils, 'getWindowSelf').returns(win);
diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js
index edfd6e8b754..8acdae76265 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/onomagicBidAdapter_spec.js b/test/spec/modules/onomagicBidAdapter_spec.js
index 2f44f7fb17b..2f382b11908 100644
--- a/test/spec/modules/onomagicBidAdapter_spec.js
+++ b/test/spec/modules/onomagicBidAdapter_spec.js
@@ -3,6 +3,7 @@ import * as utils from 'src/utils.js';
import { spec } from 'modules/onomagicBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import * as winDimensions from 'src/utils/winDimensions.js';
+import * as adUnits from 'src/utils/adUnits';
const URL = 'https://bidder.onomagic.com/hb';
@@ -61,7 +62,7 @@ describe('onomagicBidAdapter', function() {
sandbox = sinon.createSandbox();
sandbox.stub(winDimensions, 'getWinDimensions').returns(win);
- sandbox.stub(document, 'getElementById').withArgs('adunit-code').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
sandbox.stub(utils, 'getWindowTop').returns(win);
sandbox.stub(utils, 'getWindowSelf').returns(win);
});
diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js
index 19382760a2a..c801ecd2bfc 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';
@@ -1053,32 +1051,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);
});
@@ -1230,18 +1203,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 () {
@@ -1889,104 +1850,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 ef9daeca74e..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 6a04584280d..9e6092f2cad 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,22 +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 de4517e1333..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 5cd76c59dc3..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 5e8cd74ec2e..620a3d4fddf 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/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js
index 50264b9251b..2f57022d229 100644
--- a/test/spec/modules/pubmaticBidAdapter_spec.js
+++ b/test/spec/modules/pubmaticBidAdapter_spec.js
@@ -1888,13 +1888,13 @@ describe('addViewabilityToImp', () => {
});
it('should add viewability to imp.ext when measurable', () => {
- addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 });
+ addViewabilityToImp(imp, { adUnitCode: 'Div1' }, { w: 300, h: 250 });
expect(imp.ext).to.have.property('viewability');
});
it('should set viewability amount to "na" if not measurable (e.g., in iframe)', () => {
const isIframeStub = sandbox.stub(utils, 'inIframe').returns(true);
- addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 });
+ addViewabilityToImp(imp, { adUnitCode: 'Div1' }, { w: 300, h: 250 });
expect(imp.ext).to.have.property('viewability');
expect(imp.ext.viewability.amount).to.equal('na');
});
@@ -1902,13 +1902,13 @@ describe('addViewabilityToImp', () => {
it('should not add viewability if element is not found', () => {
document.getElementById.restore();
sandbox.stub(document, 'getElementById').returns(null);
- addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 });
+ addViewabilityToImp(imp, { adUnitCode: 'Div1' }, { w: 300, h: 250 });
expect(imp.ext).to.not.have.property('viewability');
});
it('should create imp.ext if not present', () => {
imp = {};
- addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 });
+ addViewabilityToImp(imp, { adUnitCode: 'Div1' }, { w: 300, h: 250 });
expect(imp.ext).to.exist;
expect(imp.ext).to.have.property('viewability');
});
diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js
deleted file mode 100644
index 7414999eb88..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:
- '',
- 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:
- '',
- 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:
- '',
- 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 24710e63388..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 862b56f6e82..ecd21896034 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/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js
index 65fc9d1a532..cc7a3309e63 100644
--- a/test/spec/modules/seedtagBidAdapter_spec.js
+++ b/test/spec/modules/seedtagBidAdapter_spec.js
@@ -4,23 +4,13 @@ import * as utils from 'src/utils.js';
import * as mockGpt from 'test/spec/integration/faker/googletag.js';
import { config } from '../../../src/config.js';
import { BIDFLOOR_CURRENCY } from '../../../modules/seedtagBidAdapter.js';
+import * as adUnits from 'src/utils/adUnits';
const PUBLISHER_ID = '0000-0000-01';
const ADUNIT_ID = '000000';
const adUnitCode = '/19968336/header-bid-tag-0'
-// create a default adunit
-const slot = document.createElement('div');
-slot.id = adUnitCode;
-slot.style.width = '300px'
-slot.style.height = '250px'
-slot.style.position = 'absolute'
-slot.style.top = '10px'
-slot.style.left = '20px'
-
-document.body.appendChild(slot);
-
function getSlotConfigs(mediaTypes, params) {
return {
params: params,
@@ -60,12 +50,25 @@ const createBannerSlotConfig = (mediatypes) => {
};
describe('Seedtag Adapter', function () {
+ let sandbox;
beforeEach(function () {
mockGpt.reset();
+ sandbox = sinon.createSandbox();
+ sandbox.stub(adUnits, 'getAdUnitElement').returns({
+ getBoundingClientRect() {
+ return {
+ top: 10,
+ left: 20,
+ width: 300,
+ height: 250
+ }
+ }
+ });
});
afterEach(function () {
mockGpt.enable();
+ sandbox.restore();
});
describe('isBidRequestValid method', function () {
describe('returns true', function () {
@@ -328,9 +331,13 @@ describe('Seedtag Adapter', function () {
});
describe('BidRequests params', function () {
- const request = spec.buildRequests(validBidRequests, bidderRequest);
- const data = JSON.parse(request.data);
- const bidRequests = data.bidRequests;
+ let request, data, bidRequests;
+ beforeEach(() => {
+ request = spec.buildRequests(validBidRequests, bidderRequest);
+ data = JSON.parse(request.data);
+ bidRequests = data.bidRequests;
+ });
+
it('should request a Banner', function () {
const bannerBid = bidRequests[0];
expect(bannerBid.id).to.equal('30b31c1838de1e');
@@ -369,27 +376,21 @@ describe('Seedtag Adapter', function () {
const bidRequests = data.bidRequests;
const bannerBid = bidRequests[0];
- // on some CI, the DOM is not initialized, so we need to check if the slot is available
- const slot = document.getElementById(adUnitCode)
- if (slot) {
- expect(bannerBid).to.have.property('geom')
-
- const params = [['width', 300], ['height', 250], ['top', 10], ['left', 20], ['scrollY', 0]]
- params.forEach(([param, value]) => {
- expect(bannerBid.geom).to.have.property(param)
- expect(bannerBid.geom[param]).to.be.a('number')
- expect(bannerBid.geom[param]).to.be.equal(value)
- })
-
- expect(bannerBid.geom).to.have.property('viewport')
- const viewportParams = ['width', 'height']
- viewportParams.forEach(param => {
- expect(bannerBid.geom.viewport).to.have.property(param)
- expect(bannerBid.geom.viewport[param]).to.be.a('number')
- })
- } else {
- expect(bannerBid).to.not.have.property('geom')
- }
+ expect(bannerBid).to.have.property('geom')
+
+ const params = [['width', 300], ['height', 250], ['top', 10], ['left', 20], ['scrollY', 0]]
+ params.forEach(([param, value]) => {
+ expect(bannerBid.geom).to.have.property(param)
+ expect(bannerBid.geom[param]).to.be.a('number')
+ expect(bannerBid.geom[param]).to.be.equal(value)
+ })
+
+ expect(bannerBid.geom).to.have.property('viewport')
+ const viewportParams = ['width', 'height']
+ viewportParams.forEach(param => {
+ expect(bannerBid.geom.viewport).to.have.property(param)
+ expect(bannerBid.geom.viewport[param]).to.be.a('number')
+ })
})
it('should have bidfloor parameter if available', function () {
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 603c6dee835..1db32e61bc2 100644
--- a/test/spec/modules/shinezRtbBidAdapter_spec.js
+++ b/test/spec/modules/shinezRtbBidAdapter_spec.js
@@ -679,6 +679,8 @@ describe('ShinezRtbBidAdapter', function () {
});
describe('unique deal id', function () {
+ let clock;
+
before(function () {
getGlobal().bidderSettings = {
shinezRtb: {
@@ -689,27 +691,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 50e48e69fd8..8edeabd466b 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..4a893aaedb9 100644
--- a/test/spec/modules/sspBCBidAdapter_spec.js
+++ b/test/spec/modules/sspBCBidAdapter_spec.js
@@ -690,14 +690,14 @@ describe('SSPBC adapter', function () {
expect(result.length).to.equal(bids.length);
expect(resultSingle.length).to.equal(1);
- expect(resultSingle[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls');
+ expect(resultSingle[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls', 'eventtrackers');
});
it('should create bid from OneCode (parameter-less) request, if response contains siteId', function () {
const resultOneCode = spec.interpretResponse(serverResponseOneCode, requestOneCode);
expect(resultOneCode.length).to.equal(1);
- expect(resultOneCode[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls');
+ expect(resultOneCode[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl', 'vurls', 'eventtrackers');
});
it('should not create bid from OneCode (parameter-less) request, if response does not contain siteId', function () {
@@ -724,7 +724,7 @@ describe('SSPBC adapter', function () {
expect(resultVideo.length).to.equal(1);
const videoBid = resultVideo[0];
- expect(videoBid).to.have.keys('adType', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml', 'vastUrl', 'vurls');
+ expect(videoBid).to.have.keys('adType', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml', 'vastUrl', 'vurls', 'eventtrackers');
expect(videoBid.adType).to.equal('instream');
expect(videoBid.mediaType).to.equal('video');
expect(videoBid.vastXml).to.match(/^<\?xml.*<\/VAST>$/);
@@ -738,7 +738,7 @@ describe('SSPBC adapter', function () {
expect(resultNative.length).to.equal(1);
const nativeBid = resultNative[0];
- expect(nativeBid).to.have.keys('cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'native', 'vurls');
+ expect(nativeBid).to.have.keys('cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'native', 'vurls', 'eventtrackers');
expect(nativeBid.native).to.have.keys('image', 'icon', 'title', 'sponsoredBy', 'body', 'clickUrl', 'impressionTrackers', 'javascriptTrackers', 'clickTrackers');
});
@@ -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 2e6a146150e..ac1d86badc0 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 9931831483c..66e0de4780a 100644
--- a/test/spec/modules/taboolaBidAdapter_spec.js
+++ b/test/spec/modules/taboolaBidAdapter_spec.js
@@ -1239,181 +1239,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 6b024a0a78c..7db3660ec7e 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 f20a2aa25aa..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 1b560937c99..e5897d077ab 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';
@@ -849,38 +848,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 8b52932ae3e..e9f205b6745 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 e4c6c2777b4..97a27f79b65 100644
--- a/test/spec/modules/twistDigitalBidAdapter_spec.js
+++ b/test/spec/modules/twistDigitalBidAdapter_spec.js
@@ -641,15 +641,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/undertoneBidAdapter_spec.js b/test/spec/modules/undertoneBidAdapter_spec.js
index f4f85a110a1..d8326ab64c8 100644
--- a/test/spec/modules/undertoneBidAdapter_spec.js
+++ b/test/spec/modules/undertoneBidAdapter_spec.js
@@ -2,6 +2,8 @@ import { expect } from 'chai';
import { spec } from 'modules/undertoneBidAdapter.js';
import { BANNER, VIDEO } from '../../../src/mediaTypes.js';
import { deepClone, getWinDimensions } from '../../../src/utils.js';
+import * as adUnits from 'src/utils/adUnits';
+import { getAdUnitElement } from 'src/utils/adUnits';
const URL = 'https://hb.undertone.com/hb';
const BIDDER_CODE = 'undertone';
@@ -314,7 +316,7 @@ describe('Undertone Adapter', () => {
};
sandbox = sinon.createSandbox();
- sandbox.stub(document, 'getElementById').withArgs('div-gpt-ad-1460505748561-0').returns(element);
+ sandbox.stub(adUnits, 'getAdUnitElement').returns(element);
});
afterEach(function() {
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 54d24f2f540..08b68058cd2 100644
--- a/test/spec/modules/vidazooBidAdapter_spec.js
+++ b/test/spec/modules/vidazooBidAdapter_spec.js
@@ -661,15 +661,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/modules/visxBidAdapter_spec.js b/test/spec/modules/visxBidAdapter_spec.js
index 48305719b57..218bc364a0c 100755
--- a/test/spec/modules/visxBidAdapter_spec.js
+++ b/test/spec/modules/visxBidAdapter_spec.js
@@ -8,6 +8,7 @@ import { mergeDeep } from '../../../src/utils.js';
import { setConfig as setCurrencyConfig } from '../../../modules/currency.js';
import { addFPDToBidderRequest } from '../../helpers/fpd.js';
import { getGlobal } from '../../../src/prebidGlobal.js';
+import * as adUnits from 'src/utils/adUnits';
describe('VisxAdapter', function () {
const adapter = newBidder(spec);
@@ -1071,13 +1072,9 @@ describe('VisxAdapter', function () {
before(function() {
sandbox = sinon.createSandbox();
- documentStub = sandbox.stub(document, 'getElementById');
- documentStub.withArgs('visx-adunit-code-1').returns({
- id: 'visx-adunit-code-1'
- });
- documentStub.withArgs('visx-adunit-element-2').returns({
- id: 'visx-adunit-element-2'
- });
+ sandbox.stub(adUnits, 'getAdUnitElement').callsFake(({ adUnitCode }) => {
+ return ['visx-adunit-code-1', 'visx-adunit-code-2'].includes(adUnitCode);
+ })
getGlobal().bidderSettings = {
visx: {
diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js
index 629831c4e36..f134be9984b 100644
--- a/test/spec/native_spec.js
+++ b/test/spec/native_spec.js
@@ -22,6 +22,7 @@ import { auctionManager } from '../../src/auctionManager.js';
import { getRenderingData } from '../../src/adRendering.js';
import { getCreativeRendererSource, PUC_MIN_VERSION } from '../../src/creativeRenderers.js';
import { deepSetValue } from '../../src/utils.js';
+import { EVENT_TYPE_IMPRESSION, TRACKER_METHOD_IMG, TRACKER_METHOD_JS } from 'src/eventTrackers.js';
const utils = require('src/utils');
const bid = {
@@ -1126,7 +1127,7 @@ describe('fireImpressionTrackers', () => {
})
function runTrackers(resp) {
- fireImpressionTrackers(resp, { runMarkup, fetchURL })
+ fireImpressionTrackers(resp, {}, { runMarkup, fetchURL })
}
it('should run markup in jstracker', () => {
@@ -1173,7 +1174,108 @@ describe('fireImpressionTrackers', () => {
});
sinon.assert.notCalled(fetchURL);
sinon.assert.notCalled(runMarkup);
- })
+ });
+
+ describe('when bidResponse mediaTypes.native.ortb.eventtrackers filters allowed trackers', () => {
+ let indexStub;
+ let getMediaTypesStub;
+
+ beforeEach(() => {
+ getMediaTypesStub = sinon.stub();
+ indexStub = sinon.stub(auctionManager, 'index').get(() => ({ getMediaTypes: getMediaTypesStub }));
+ });
+
+ afterEach(() => {
+ indexStub.restore();
+ });
+
+ it('should fire only impression+IMG eventtrackers when request allows only IMG for impression', () => {
+ getMediaTypesStub.returns({
+ native: {
+ ortb: {
+ eventtrackers: [{ event: EVENT_TYPE_IMPRESSION, methods: [TRACKER_METHOD_IMG] }]
+ }
+ }
+ });
+ const bidResponse = { adUnitId: 'au', requestId: 'req' };
+ fireImpressionTrackers({
+ eventtrackers: [
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'img-url' },
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_JS, url: 'js-url' }
+ ]
+ }, bidResponse, { runMarkup, fetchURL });
+ sinon.assert.calledOnceWithExactly(fetchURL, 'img-url');
+ sinon.assert.notCalled(runMarkup);
+ });
+
+ it('should fire only impression+JS eventtrackers when request allows only JS for impression', () => {
+ getMediaTypesStub.returns({
+ native: {
+ ortb: {
+ eventtrackers: [{ event: EVENT_TYPE_IMPRESSION, methods: [TRACKER_METHOD_JS] }]
+ }
+ }
+ });
+ const bidResponse = { adUnitId: 'au', requestId: 'req' };
+ fireImpressionTrackers({
+ eventtrackers: [
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'img-url' },
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_JS, url: 'js-url' }
+ ]
+ }, bidResponse, { runMarkup, fetchURL });
+ sinon.assert.notCalled(fetchURL);
+ sinon.assert.calledWith(runMarkup, sinon.match('script async src="js-url"'));
+ });
+
+ it('should not fire any eventtrackers when request eventtrackers do not include impression', () => {
+ getMediaTypesStub.returns({
+ native: {
+ ortb: {
+ eventtrackers: [{ event: 2, methods: [TRACKER_METHOD_IMG, TRACKER_METHOD_JS] }]
+ }
+ }
+ });
+ const bidResponse = { adUnitId: 'au', requestId: 'req' };
+ fireImpressionTrackers({
+ eventtrackers: [
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'imp-img-url' }
+ ]
+ }, bidResponse, { runMarkup, fetchURL });
+ sinon.assert.notCalled(fetchURL);
+ sinon.assert.notCalled(runMarkup);
+ });
+
+ it('should still fire legacy imptrackers and jstracker when eventtrackers are filtered out', () => {
+ getMediaTypesStub.returns({
+ native: {
+ ortb: {
+ eventtrackers: []
+ }
+ }
+ });
+ const bidResponse = { adUnitId: 'au', requestId: 'req' };
+ fireImpressionTrackers({
+ eventtrackers: [{ event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'from-eventtrackers' }],
+ imptrackers: ['legacy-imp-url'],
+ jstracker: 'legacy-js-markup'
+ }, bidResponse, { runMarkup, fetchURL });
+ sinon.assert.calledOnceWithExactly(fetchURL, 'legacy-imp-url');
+ sinon.assert.calledWith(runMarkup, 'legacy-js-markup');
+ });
+
+ it('should use default allowed trackers when getMediaTypes returns empty', () => {
+ getMediaTypesStub.returns({});
+ const bidResponse = { adUnitId: 'au', requestId: 'req' };
+ fireImpressionTrackers({
+ eventtrackers: [
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_IMG, url: 'default-img' },
+ { event: EVENT_TYPE_IMPRESSION, method: TRACKER_METHOD_JS, url: 'default-js' }
+ ]
+ }, bidResponse, { runMarkup, fetchURL });
+ sinon.assert.calledWith(fetchURL, 'default-img');
+ sinon.assert.calledWith(runMarkup, sinon.match('script async src="default-js"'));
+ });
+ });
})
describe('fireClickTrackers', () => {
diff --git a/test/spec/unit/adRendering_spec.js b/test/spec/unit/adRendering_spec.js
index 2943f27283b..3a04342c800 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/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js
index f159b8a0870..4c7757e1bb5 100644
--- a/test/spec/unit/core/adapterManager_spec.js
+++ b/test/spec/unit/core/adapterManager_spec.js
@@ -32,6 +32,7 @@ import {
TRACKER_METHOD_IMG,
TRACKER_METHOD_JS
} from '../../../../src/eventTrackers.js';
+import 'src/prebid.js';
var events = require('../../../../src/events.js');
const CONFIG = {
@@ -1816,6 +1817,18 @@ describe('adapterManager tests', function () {
expect(sizes1).not.to.deep.equal(sizes2);
});
+ it('should transfer element from ad unit', () => {
+ adUnits[0].element = 'test';
+ const requests = makeBidRequests();
+ requests.flatMap(req => req.bids).forEach(bidRequest => {
+ if (bidRequest.adUnitCode === adUnits[0].code) {
+ expect(bidRequest.element).to.equal('test');
+ } else {
+ expect(bidRequest.element).to.not.exist;
+ }
+ });
+ })
+
it('should transfer deferBilling from ad unit', () => {
adUnits[0].deferBilling = true;
const requests = makeBidRequests();
diff --git a/test/spec/unit/core/ajax_spec.js b/test/spec/unit/core/ajax_spec.js
index d2e891f0d78..476b0de005f 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 c2974906451..383d7441a62 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);
- });
- });
- });
- });
});
});
@@ -1744,6 +1691,114 @@ describe('bidderFactory', () => {
});
});
})
+
+ describe('media type validation', () => {
+ let req;
+
+ function mkResponse(props) {
+ return Object.assign({
+ requestId: req.bidId,
+ cpm: 1,
+ ttl: 60,
+ creativeId: '123',
+ netRevenue: true,
+ currency: 'USD',
+ width: 1,
+ height: 2,
+ mediaType: 'banner',
+ }, props);
+ }
+
+ function checkValid(bid, opts = {}) {
+ return isValid('au', bid, {
+ index: stubAuctionIndex({ bidRequests: [req] }),
+ ...opts,
+ });
+ }
+
+ beforeEach(() => {
+ req = {
+ ...MOCK_BIDS_REQUEST.bids[0],
+ mediaTypes: {
+ banner: {
+ sizes: [[1, 2]]
+ }
+ }
+ };
+ });
+
+ it('should reject video bid when ad unit only has banner', () => {
+ expect(checkValid(mkResponse({ mediaType: 'video' }))).to.be.false;
+ });
+
+ it('should accept video bid when ad unit has both banner and video', () => {
+ req.mediaTypes = {
+ banner: { sizes: [[1, 2]] },
+ video: { context: 'instream' }
+ };
+ expect(checkValid(mkResponse({ mediaType: 'video', vastUrl: 'http://vast.xml' }))).to.be.true;
+ });
+
+ it('should skip media type check when adapter omits mediaType', () => {
+ req.mediaTypes = {
+ video: { context: 'instream' }
+ };
+
+ expect(checkValid(mkResponse({ mediaType: 'banner' }), { responseMediaType: null })).to.be.true;
+ });
+
+ it('should reject unknown media type when configured and adapter omits mediaType', () => {
+ req.mediaTypes = {
+ video: { context: 'instream' }
+ };
+ config.setConfig({
+ auctionOptions: {
+ rejectUnknownMediaTypes: true
+ }
+ });
+
+ expect(checkValid(mkResponse({ mediaType: 'banner' }), { responseMediaType: null })).to.be.false;
+ });
+
+ it('should keep legacy behavior when rejectUnknownMediaTypes is disabled', () => {
+ req.mediaTypes = {
+ video: { context: 'instream' }
+ };
+ config.setConfig({
+ auctionOptions: {
+ rejectUnknownMediaTypes: false
+ }
+ });
+
+ expect(checkValid(mkResponse({ mediaType: 'banner' }), { responseMediaType: null })).to.be.true;
+ });
+
+ it('should allow mismatched media type when rejectInvalidMediaTypes is disabled', () => {
+ req.mediaTypes = {
+ banner: { sizes: [[1, 2]] }
+ };
+ config.setConfig({
+ auctionOptions: {
+ rejectInvalidMediaTypes: false
+ }
+ });
+
+ expect(checkValid(mkResponse({ mediaType: 'video' }))).to.be.true;
+ });
+
+ it('should reject mismatched media type when rejectInvalidMediaTypes is enabled', () => {
+ req.mediaTypes = {
+ banner: { sizes: [[1, 2]] }
+ };
+ config.setConfig({
+ auctionOptions: {
+ rejectInvalidMediaTypes: true
+ }
+ });
+
+ expect(checkValid(mkResponse({ mediaType: 'video' }))).to.be.false;
+ });
+ });
});
describe('gzip compression', () => {
diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js
index 28937d70f8b..473a66efab7 100644
--- a/test/spec/unit/core/targeting_spec.js
+++ b/test/spec/unit/core/targeting_spec.js
@@ -1728,22 +1728,22 @@ describe('targeting tests', function () {
it('can find slots by ad unit path', () => {
const paths = ['slot/1', 'slot/2']
- expect(getGPTSlotsForAdUnits(paths, null, () => slots)).to.eql({ [paths[0]]: [slots[0], slots[2]], [paths[1]]: [slots[1]] });
+ expect(getGPTSlotsForAdUnits(paths, () => slots)).to.eql({ [paths[0]]: [slots[0], slots[2]], [paths[1]]: [slots[1]] });
})
it('can find slots by ad element ID', () => {
const elementIds = ['div-1', 'div-2']
- expect(getGPTSlotsForAdUnits(elementIds, null, () => slots)).to.eql({ [elementIds[0]]: [slots[0]], [elementIds[1]]: [slots[1]] });
+ expect(getGPTSlotsForAdUnits(elementIds, () => slots)).to.eql({ [elementIds[0]]: [slots[0]], [elementIds[1]]: [slots[1]] });
})
it('returns empty list on no match', () => {
- expect(getGPTSlotsForAdUnits(['missing', 'slot/2'], null, () => slots)).to.eql({
+ expect(getGPTSlotsForAdUnits(['missing', 'slot/2'], () => slots)).to.eql({
missing: [],
'slot/2': [slots[1]]
});
});
- it('can use customSlotMatching resolving to ad unit codes', () => {
+ it('can use customGptSlotMatching resolving to ad unit codes', () => {
const csm = (slot) => {
if (slot.getAdUnitPath() === 'slot/1') {
return (au) => {
@@ -1751,13 +1751,17 @@ describe('targeting tests', function () {
}
}
}
- expect(getGPTSlotsForAdUnits(['div-2', 'custom'], csm, () => slots)).to.eql({
+ config.setConfig({
+ customGptSlotMatching: csm
+ })
+ expect(getGPTSlotsForAdUnits(['div-2', 'custom'], () => slots)).to.eql({
'custom': [slots[0], slots[2]],
'div-2': [slots[1]]
})
+ config.resetConfig();
});
- it('can use customSlotMatching resolving to elementIds', () => {
+ it('can use customGptSlotMatching resolving to elementIds', () => {
const csm = (slot) => {
if (slot.getSlotElementId() === 'div-1') {
return (au) => {
@@ -1765,14 +1769,18 @@ describe('targeting tests', function () {
}
}
}
- expect(getGPTSlotsForAdUnits(['div-2', 'custom'], csm, () => slots)).to.eql({
+ config.setConfig({
+ customGptSlotMatching: csm
+ })
+ expect(getGPTSlotsForAdUnits(['div-2', 'custom'], () => slots)).to.eql({
'custom': [slots[0]],
'div-2': [slots[1]]
})
+ config.resetConfig();
});
it('can handle repeated adUnitCodes', () => {
- expect(getGPTSlotsForAdUnits(['div-1', 'div-1'], null, () => slots)).to.eql({
+ expect(getGPTSlotsForAdUnits(['div-1', 'div-1'], () => slots)).to.eql({
'div-1': [slots[0]]
})
})
diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js
index e0fc7ab0da2..bbc4d3cc424 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;
@@ -82,6 +81,24 @@ var Slot = function Slot(elementId, pathId) {
return Object.getOwnPropertyNames(this.targeting);
},
+ getConfig: function getConfig(key) {
+ if (key === 'targeting') {
+ return this.targeting;
+ }
+ },
+
+ setConfig: function setConfig(config) {
+ if (config?.targeting) {
+ Object.keys(config.targeting).forEach((key) => {
+ if (config.targeting[key] == null) {
+ delete this.targeting[key];
+ } else {
+ this.setTargeting(key, config.targeting[key]);
+ }
+ });
+ }
+ },
+
clearTargeting: function clearTargeting() {
this.targeting = {};
return this;
@@ -118,6 +135,24 @@ var createSlotArrayScenario2 = function createSlotArrayScenario2() {
window.googletag = {
_slots: [],
_targeting: {},
+ getConfig: function (key) {
+ if (key === 'targeting') {
+ return this._targeting;
+ }
+ },
+ setConfig: function (config) {
+ if (config?.targeting) {
+ Object.keys(config.targeting).forEach((key) => {
+ if (config.targeting[key] == null) {
+ delete this._targeting[key];
+ } else {
+ this._targeting[key] = Array.isArray(config.targeting[key])
+ ? config.targeting[key]
+ : [config.targeting[key]];
+ }
+ });
+ }
+ },
pubads: function () {
var self = this;
return {
@@ -1066,11 +1101,18 @@ describe('Unit: Prebid Module', function () {
});
});
- it('should set googletag targeting keys to specific slot with customSlotMatching', function () {
+ it('should set googletag targeting keys to specific slot with customGptSlotMatching', function () {
// same ad unit code but two differnt divs
- // we make sure we can set targeting for a specific one with customSlotMatching
+ // we make sure we can set targeting for a specific one with customGptSlotMatching
- pbjs.setConfig({ enableSendAllBids: false });
+ pbjs.setConfig({
+ enableSendAllBids: false,
+ customGptSlotMatching: (slot) => {
+ return (adUnitCode) => {
+ return slots[0].getSlotElementId() === slot.getSlotElementId();
+ };
+ }
+ });
var slots = createSlotArrayScenario2();
@@ -1078,11 +1120,7 @@ describe('Unit: Prebid Module', function () {
slots[1].spySetTargeting.resetHistory();
window.googletag.pubads().setSlots(slots);
pbjs.setConfig({ targetingControls: { allBidsCustomTargeting: true } });
- pbjs.setTargetingForGPTAsync([config.adUnitCodes[0]], (slot) => {
- return (adUnitCode) => {
- return slots[0].getSlotElementId() === slot.getSlotElementId();
- };
- });
+ pbjs.setTargetingForGPTAsync([config.adUnitCodes[0]]);
var expected = getTargetingKeys();
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
@@ -3240,14 +3278,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 085b5734e5a..d451424772d 100644
--- a/test/spec/unit/secureCreatives_spec.js
+++ b/test/spec/unit/secureCreatives_spec.js
@@ -10,28 +10,17 @@ import { config as configObj } from 'src/config.js';
import * as creativeRenderers from 'src/creativeRenderers.js';
import 'src/prebid.js';
import 'modules/nativeRendering.js';
+import * as adUnits from 'src/utils/adUnits';
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();
});
@@ -552,6 +541,7 @@ describe('secureCreatives', () => {
value = Array.isArray(value) ? value : [value];
targeting[key] = value;
}),
+ getConfig: sinon.stub().callsFake((key) => key === 'targeting' ? targeting : null),
getTargetingKeys: sinon.stub().callsFake(() => Object.keys(targeting)),
getTargeting: sinon.stub().callsFake((key) => targeting[key] || [])
}
diff --git a/test/spec/utils/adUnits_spec.js b/test/spec/utils/adUnits_spec.js
new file mode 100644
index 00000000000..f2652baf3a0
--- /dev/null
+++ b/test/spec/utils/adUnits_spec.js
@@ -0,0 +1,40 @@
+import { getAdUnitElement } from '../../../src/utils/adUnits.js';
+
+describe('ad unit utils', () => {
+ let sandbox;
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+ describe('getAdUnitElement', () => {
+ beforeEach(() => {
+ sandbox.stub(document, 'getElementById').callsFake((id) => ({ id }));
+ });
+ it('should return null on invalid input', () => {
+ expect(getAdUnitElement({})).to.eql(null);
+ });
+ it('should prefer element', () => {
+ expect(getAdUnitElement({
+ element: 'explicit',
+ code: 'ignored',
+ adUnitCode: 'ignored'
+ })).to.eql('explicit');
+ });
+ it('should fallback to code as id', () => {
+ expect(getAdUnitElement({
+ code: 'au'
+ })).to.eql({
+ id: 'au'
+ });
+ });
+ it('should fallback to adUnitCode as id', () => {
+ expect(getAdUnitElement({
+ adUnitCode: 'au'
+ })).to.eql({
+ id: 'au'
+ })
+ })
+ });
+});
diff --git a/test/test_deps.js b/test/test_deps.js
index 2c16b6e9587..f75279193fc 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');