diff --git a/integrationExamples/gpt/azerionedgeRtdProvider_example.html b/integrationExamples/gpt/azerionedgeRtdProvider_example.html
new file mode 100644
index 00000000000..880fe5ed706
--- /dev/null
+++ b/integrationExamples/gpt/azerionedgeRtdProvider_example.html
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Azerion Edge RTD
+
+
+
+
+
+ Segments:
+
+
+
diff --git a/integrationExamples/gpt/publir_hello_world.html b/integrationExamples/gpt/publir_hello_world.html
new file mode 100644
index 00000000000..4763525408d
--- /dev/null
+++ b/integrationExamples/gpt/publir_hello_world.html
@@ -0,0 +1,84 @@
+
+
+
+
+ Prebid.js Banner gpt Example
+
+
+
+
+
+
+
+
+
+
+ Prebid.js Test
+ Div-1
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries/appnexusUtils/anKeywords.js b/libraries/appnexusUtils/anKeywords.js
index d6714dacc21..a6fa8d7a21e 100644
--- a/libraries/appnexusUtils/anKeywords.js
+++ b/libraries/appnexusUtils/anKeywords.js
@@ -78,7 +78,7 @@ export function convertKeywordStringToANMap(keyStr) {
}
/**
- * @param {Array} kwarray: keywords as an array of strings
+ * @param {Array} kwarray keywords as an array of strings
* @return {{}} appnexus-style keyword map
*/
function convertKeywordsToANMap(kwarray) {
diff --git a/libraries/autoplayDetection/autoplay.js b/libraries/autoplayDetection/autoplay.js
new file mode 100644
index 00000000000..b598e46cbd1
--- /dev/null
+++ b/libraries/autoplayDetection/autoplay.js
@@ -0,0 +1,42 @@
+let autoplayEnabled = null;
+
+/**
+ * Note: this function returns true if detection is not done yet. This is by design: if autoplay is not allowed,
+ * the call to video.play() will fail immediately, otherwise it may not terminate.
+ * @returns true if autoplay is not forbidden
+ */
+export const isAutoplayEnabled = () => autoplayEnabled !== false;
+
+// generated with:
+// ask ChatGPT for a 160x90 black PNG image (1/8th the size of 720p)
+//
+// encode with:
+// ffmpeg -i black_image_160x90.png -r 1 -c:v libx264 -bsf:v 'filter_units=remove_types=6' -pix_fmt yuv420p autoplay.mp4
+// this creates a 1 second long, 1 fps YUV 4:2:0 video encoded with H.264 without encoder details.
+//
+// followed by:
+// echo "data:video/mp4;base64,$(base64 -i autoplay.mp4)"
+
+const autoplayVideoUrl =
+ 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAADxtZGF0AAAAMGWIhAAV//73ye/Apuvb3rW/k89I/Cy3PsIqP39atohOSV14BYa1heKCYgALQC5K4QAAAwZtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAD6AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACMHRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAD6AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAoAAAAFoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAA+gAAAAAAAEAAAAAAahtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAAEAAAABAAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAFTbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABE3N0YmwAAACvc3RzZAAAAAAAAAABAAAAn2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAoABaAEgAAABIAAAAAAAAAAEVTGF2YzYwLjMxLjEwMiBsaWJ4MjY0AAAAAAAAAAAAAAAY//8AAAA1YXZjQwFkAAr/4QAYZ2QACqzZQo35IQAAAwABAAADAAIPEiWWAQAGaOvjyyLA/fj4AAAAABRidHJ0AAAAAAAAAaAAAAGgAAAAGHN0dHMAAAAAAAAAAQAAAAEAAEAAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAABRzdHN6AAAAAAAAADQAAAABAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjYwLjE2LjEwMA==';
+
+function startDetection() {
+ // we create an HTMLVideoElement muted and not displayed in which we try to play a one frame video
+ const videoElement = document.createElement('video');
+ videoElement.src = autoplayVideoUrl;
+ videoElement.setAttribute('playsinline', 'true');
+ videoElement.muted = true;
+
+ videoElement
+ .play()
+ .then(() => {
+ autoplayEnabled = true;
+ videoElement.pause();
+ })
+ .catch(() => {
+ autoplayEnabled = false;
+ });
+}
+
+// starts detection as soon as this library is loaded
+startDetection();
diff --git a/libraries/keywords/keywords.js b/libraries/keywords/keywords.js
index 645c9c8d38f..b317bcf0c6b 100644
--- a/libraries/keywords/keywords.js
+++ b/libraries/keywords/keywords.js
@@ -6,7 +6,7 @@ const ORTB_KEYWORDS_PATHS = ['user.keywords'].concat(
);
/**
- * @param commaSeparatedKeywords: any number of either keyword arrays, or comma-separated keyword strings
+ * @param commaSeparatedKeywords any number of either keyword arrays, or comma-separated keyword strings
* @returns an array with all unique keywords contained across all inputs
*/
export function mergeKeywords(...commaSeparatedKeywords) {
diff --git a/libraries/objectGuard/objectGuard.js b/libraries/objectGuard/objectGuard.js
index cf3d2f38256..784c3f1444d 100644
--- a/libraries/objectGuard/objectGuard.js
+++ b/libraries/objectGuard/objectGuard.js
@@ -2,6 +2,8 @@ import {isData, objectTransformer, sessionedApplies} from '../../src/activities/
import {deepAccess, deepClone, deepEqual, deepSetValue} from '../../src/utils.js';
/**
+ * @typedef {import('../src/activities/redactor.js').TransformationRuleDef} TransformationRuleDef
+ * @typedef {import('../src/adapters/bidderFactory.js').TransformationRule} TransformationRule
* @typedef {Object} ObjectGuard
* @property {*} obj a view on the guarded object
* @property {function(): void} verify a function that checks for and rolls back disallowed changes to the guarded object
diff --git a/libraries/objectGuard/ortbGuard.js b/libraries/objectGuard/ortbGuard.js
index 7911b378c3d..62918d55548 100644
--- a/libraries/objectGuard/ortbGuard.js
+++ b/libraries/objectGuard/ortbGuard.js
@@ -9,6 +9,10 @@ import {
import {objectGuard, writeProtectRule} from './objectGuard.js';
import {mergeDeep} from '../../src/utils.js';
+/**
+ * @typedef {import('./objectGuard.js').ObjectGuard} ObjectGuard
+ */
+
function ortb2EnrichRules(isAllowed = isActivityAllowed) {
return [
{
diff --git a/libraries/uid1Eids/uid1Eids.js b/libraries/uid1Eids/uid1Eids.js
new file mode 100644
index 00000000000..5bf3dde5c6c
--- /dev/null
+++ b/libraries/uid1Eids/uid1Eids.js
@@ -0,0 +1,16 @@
+export const UID1_EIDS = {
+ 'tdid': {
+ source: 'adserver.org',
+ atype: 1,
+ getValue: function(data) {
+ if (data.id) {
+ return data.id;
+ } else {
+ return data;
+ }
+ },
+ getUidExt: function(data) {
+ return {...{rtiPartner: 'TDID'}, ...data.ext}
+ }
+ }
+}
diff --git a/libraries/video/shared/parentModule.js b/libraries/video/shared/parentModule.js
index 06c71ebd75b..b040f39bcb8 100644
--- a/libraries/video/shared/parentModule.js
+++ b/libraries/video/shared/parentModule.js
@@ -47,6 +47,7 @@ export function ParentModule(submoduleBuilder_) {
}
/**
+ * @typedef {import('../../../modules/videoModule/coreVideo.js').vendorSubmoduleDirectory} vendorSubmoduleDirectory
* @typedef {Object} SubmoduleBuilder
* @summary Instantiates submodules
* @param {vendorSubmoduleDirectory} submoduleDirectory_
diff --git a/modules/.submodules.json b/modules/.submodules.json
index 61d8c843d47..cfa98b5ab32 100644
--- a/modules/.submodules.json
+++ b/modules/.submodules.json
@@ -63,6 +63,7 @@
"airgridRtdProvider",
"akamaiDapRtdProvider",
"arcspanRtdProvider",
+ "azerionedgeRtdProvider",
"blueconicRtdProvider",
"brandmetricsRtdProvider",
"browsiRtdProvider",
diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js
index acd89ef72df..6e3c38e4e85 100644
--- a/modules/adagioBidAdapter.js
+++ b/modules/adagioBidAdapter.js
@@ -77,7 +77,7 @@ export const ORTB_VIDEO_PARAMS = {
'boxingallowed': (value) => isInteger(value),
'playbackmethod': (value) => isArrayOfNums(value),
'playbackend': (value) => isInteger(value),
- 'delivery': (value) => isInteger(value),
+ 'delivery': (value) => isArrayOfNums(value),
'pos': (value) => isInteger(value),
'api': (value) => isArrayOfNums(value)
};
diff --git a/modules/adfBidAdapter.js b/modules/adfBidAdapter.js
index 0484c383762..881b1adfcc4 100644
--- a/modules/adfBidAdapter.js
+++ b/modules/adfBidAdapter.js
@@ -230,7 +230,14 @@ export const spec = {
ortb: bidResponse.native
};
} else {
- result[ mediaType === VIDEO ? 'vastXml' : 'ad' ] = bidResponse.adm;
+ if (mediaType === VIDEO) {
+ result.vastXml = bidResponse.adm;
+ if (bidResponse.nurl) {
+ result.vastUrl = bidResponse.nurl;
+ }
+ } else {
+ result.ad = bidResponse.adm;
+ }
}
if (!bid.renderer && mediaType === VIDEO && deepAccess(bid, 'mediaTypes.video.context') === 'outstream') {
diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js
index d6a4030057a..62e0ab29f8a 100644
--- a/modules/adkernelBidAdapter.js
+++ b/modules/adkernelBidAdapter.js
@@ -111,7 +111,8 @@ export const spec = {
{code: 'didnadisplay'},
{code: 'qortex'},
{code: 'adpluto'},
- {code: 'headbidder'}
+ {code: 'headbidder'},
+ {code: 'digiad'}
],
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js
index 3f87476def7..6c268b2d382 100644
--- a/modules/admaticBidAdapter.js
+++ b/modules/admaticBidAdapter.js
@@ -2,6 +2,7 @@ import {getValue, formatQS, logError, deepAccess, isArray, getBidIdParameter} fr
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { config } from '../src/config.js';
import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js';
+import { Renderer } from '../src/Renderer.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
@@ -33,11 +34,13 @@ export const OPENRTB = {
let SYNC_URL = '';
const BIDDER_CODE = 'admatic';
+const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
export const spec = {
code: BIDDER_CODE,
+ gvlid: 1281,
aliases: [
- {code: 'pixad'}
+ {code: 'pixad', gvlid: 1281}
],
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
/**
@@ -190,38 +193,45 @@ export const spec = {
interpretResponse: (response, request) => {
const body = response.body;
const bidResponses = [];
+
if (body && body?.data && isArray(body.data)) {
body.data.forEach(bid => {
- const resbid = {
- requestId: bid.id,
- cpm: bid.price,
- width: bid.width,
- height: bid.height,
- currency: body.cur || 'TRY',
- netRevenue: true,
- creativeId: bid.creative_id,
- meta: {
- model: bid.mime_type,
- advertiserDomains: bid && bid.adomain ? bid.adomain : []
- },
- bidder: bid.bidder,
- mediaType: bid.type,
- ttl: 60
- };
-
- if (resbid.mediaType === 'video' && isUrl(bid.party_tag)) {
- resbid.vastUrl = bid.party_tag;
- resbid.vastImpUrl = bid.iurl;
- } else if (resbid.mediaType === 'video') {
- resbid.vastXml = bid.party_tag;
- resbid.vastImpUrl = bid.iurl;
- } else if (resbid.mediaType === 'banner') {
- resbid.ad = bid.party_tag;
- } else if (resbid.mediaType === 'native') {
- resbid.native = interpretNativeAd(bid.party_tag)
- };
+ const bidRequest = getAssociatedBidRequest(request.data.imp, bid);
+ if (bidRequest) {
+ const resbid = {
+ requestId: bid.id,
+ cpm: bid.price,
+ width: bid.width,
+ height: bid.height,
+ currency: body.cur || 'TRY',
+ netRevenue: true,
+ creativeId: bid.creative_id,
+ meta: {
+ model: bid.mime_type,
+ advertiserDomains: bid && bid.adomain ? bid.adomain : []
+ },
+ bidder: bid.bidder,
+ mediaType: bid.type,
+ ttl: 60
+ };
+
+ if (resbid.mediaType === 'video' && isUrl(bid.party_tag)) {
+ resbid.vastUrl = bid.party_tag;
+ } else if (resbid.mediaType === 'video') {
+ resbid.vastXml = bid.party_tag;
+ } else if (resbid.mediaType === 'banner') {
+ resbid.ad = bid.party_tag;
+ } else if (resbid.mediaType === 'native') {
+ resbid.native = interpretNativeAd(bid.party_tag)
+ };
+
+ const context = deepAccess(bidRequest, 'mediatype.context');
+ if (resbid.mediaType === 'video' && context === 'outstream') {
+ resbid.renderer = createOutstreamVideoRenderer(bid);
+ }
- bidResponses.push(resbid);
+ bidResponses.push(resbid);
+ }
});
}
return bidResponses;
@@ -272,6 +282,40 @@ function isUrl(str) {
}
};
+function outstreamRender (bid) {
+ bid.renderer.push(() => {
+ window.ANOutstreamVideo.renderAd({
+ targetId: bid.adUnitCode,
+ adResponse: bid.adResponse
+ });
+ });
+}
+
+function createOutstreamVideoRenderer(bid) {
+ const renderer = Renderer.install({
+ id: bid.bidId,
+ url: RENDERER_URL,
+ loaded: false
+ });
+
+ try {
+ renderer.setRender(outstreamRender);
+ } catch (err) {
+ logError('Prebid Error calling setRender on renderer' + err);
+ }
+
+ return renderer;
+}
+
+function getAssociatedBidRequest(bidRequests, bid) {
+ for (const request of bidRequests) {
+ if (request.id === bid.id) {
+ return request;
+ }
+ }
+ return undefined;
+}
+
function enrichSlotWithFloors(slot, bidRequest) {
try {
const slotFloors = {};
diff --git a/modules/adnowBidAdapter.js b/modules/adnowBidAdapter.js
index 99f56df58b2..5083f4cc93d 100644
--- a/modules/adnowBidAdapter.js
+++ b/modules/adnowBidAdapter.js
@@ -5,7 +5,7 @@ import {includes} from '../src/polyfill.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
const BIDDER_CODE = 'adnow';
-const ENDPOINT = 'https://n.ads3-adnow.com/a';
+const ENDPOINT = 'https://n.nnowa.com/a';
/**
* @typedef {object} CommonBidData
diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js
index 02dd7453be8..eb5f3c19dea 100644
--- a/modules/adnuntiusBidAdapter.js
+++ b/modules/adnuntiusBidAdapter.js
@@ -105,15 +105,16 @@ const storageTool = (function () {
const getUsi = function (meta, ortb2, bidderRequest) {
// Fetch user id from parameters.
- const paramUsi = (bidderRequest.bids) ? bidderRequest.bids.find(bid => {
- if (bid.params && bid.params.userId) return true
- }).params.userId : false
- let usi = (meta && meta.usi) ? meta.usi : false
+ for (let i = 0; i < (bidderRequest.bids || []).length; i++) {
+ const bid = bidderRequest.bids[i];
+ if (bid.params && bid.params.userId) {
+ return bid.params.userId;
+ }
+ }
if (ortb2 && ortb2.user && ortb2.user.id) {
- usi = ortb2.user.id
+ return ortb2.user.id
}
- if (paramUsi) usi = paramUsi
- return usi;
+ return (meta && meta.usi) ? meta.usi : false
}
const getSegmentsFromOrtb = function (ortb2) {
diff --git a/modules/adotBidAdapter.js b/modules/adotBidAdapter.js
index b48a7ec43b0..9f2810e13df 100644
--- a/modules/adotBidAdapter.js
+++ b/modules/adotBidAdapter.js
@@ -7,6 +7,23 @@ import {config} from '../src/config.js';
import {OUTSTREAM} from '../src/video.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
+/**
+ * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
+ * @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
+ * @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
+ * @typedef {import('../src/adapters/bidderFactory.js').MediaType} MediaType
+ * @typedef {import('../src/adapters/bidderFactory.js').Site} Site
+ * @typedef {import('../src/adapters/bidderFactory.js').Device} Device
+ * @typedef {import('../src/adapters/bidderFactory.js').User} User
+ * @typedef {import('../src/adapters/bidderFactory.js').Banner} Banner
+ * @typedef {import('../src/adapters/bidderFactory.js').Video} Video
+ * @typedef {import('../src/adapters/bidderFactory.js').AdUnit} AdUnit
+ * @typedef {import('../src/adapters/bidderFactory.js').Imp} Imp
+ */
+
const BIDDER_CODE = 'adot';
const ADAPTER_VERSION = 'v2.0.0';
const GVLID = 272;
diff --git a/modules/adqueryBidAdapter.js b/modules/adqueryBidAdapter.js
index bfcc56050fb..f19cf020ca8 100644
--- a/modules/adqueryBidAdapter.js
+++ b/modules/adqueryBidAdapter.js
@@ -134,10 +134,9 @@ export const spec = {
*/
onBidWon: (bid) => {
logInfo('onBidWon', bid);
- const bidString = JSON.stringify(bid);
- let copyOfBid = JSON.parse(bidString);
- delete copyOfBid.ad;
- const shortBidString = JSON.stringify(bid);
+ let copyOfBid = { ...bid }
+ delete copyOfBid.ad
+ const shortBidString = JSON.stringify(copyOfBid);
const encodedBuf = window.btoa(shortBidString);
let params = {
diff --git a/modules/adriverIdSystem.js b/modules/adriverIdSystem.js
index 1da75f2063d..2dab76b7862 100644
--- a/modules/adriverIdSystem.js
+++ b/modules/adriverIdSystem.js
@@ -42,7 +42,6 @@ export const adriverIdSubmodule = {
* performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleConfig} [config]
- * @param {ConsentData} [consentData]
* @returns {IdResponse|undefined}
*/
getId(config) {
diff --git a/modules/adspiritBidAdapter.js b/modules/adspiritBidAdapter.js
new file mode 100644
index 00000000000..c39ceca8600
--- /dev/null
+++ b/modules/adspiritBidAdapter.js
@@ -0,0 +1,124 @@
+import * as utils from '../src/utils.js';
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { BANNER, NATIVE } from '../src/mediaTypes.js';
+
+const RTB_URL = '/rtb/getbid.php?rtbprovider=prebid';
+const SCRIPT_URL = '/adasync.min.js';
+
+export const spec = {
+
+ code: 'adspirit',
+ aliases: ['twiago'],
+ supportedMediaTypes: [BANNER, NATIVE],
+
+ isBidRequestValid: function (bid) {
+ let host = spec.getBidderHost(bid);
+ if (!host || !bid.params.placementId) {
+ return false;
+ }
+ return true;
+ },
+
+ buildRequests: function (validBidRequests, bidderRequest) {
+ let requests = [];
+ for (let i = 0; i < validBidRequests.length; i++) {
+ let bidRequest = validBidRequests[i];
+ bidRequest.adspiritConId = spec.genAdConId(bidRequest);
+ let reqUrl = spec.getBidderHost(bidRequest);
+ let placementId = utils.getBidIdParameter('placementId', bidRequest.params);
+ reqUrl = '//' + reqUrl + RTB_URL + '&pid=' + placementId +
+ '&ref=' + encodeURIComponent(bidderRequest.refererInfo.topmostLocation) +
+ '&scx=' + (screen.width) +
+ '&scy=' + (screen.height) +
+ '&wcx=' + (window.innerWidth || document.documentElement.clientWidth) +
+ '&wcy=' + (window.innerHeight || document.documentElement.clientHeight) +
+ '&async=' + bidRequest.adspiritConId +
+ '&t=' + Math.round(Math.random() * 100000);
+
+ let data = {};
+
+ if (bidderRequest && bidderRequest.gdprConsent) {
+ const gdprConsentString = bidderRequest.gdprConsent.consentString;
+ reqUrl += '&gdpr=' + encodeURIComponent(gdprConsentString);
+ }
+
+ if (bidRequest.schain && bidderRequest.schain) {
+ data.schain = bidRequest.schain;
+ }
+
+ requests.push({
+ method: 'GET',
+ url: reqUrl,
+ data: data,
+ bidRequest: bidRequest
+ });
+ }
+ return requests;
+ },
+ interpretResponse: function(serverResponse, bidRequest) {
+ const bidResponses = [];
+ let bidObj = bidRequest.bidRequest;
+
+ if (!serverResponse || !serverResponse.body || !bidObj) {
+ utils.logWarn(`No valid bids from ${spec.code} bidder!`);
+ return [];
+ }
+
+ let adData = serverResponse.body;
+ let cpm = adData.cpm;
+
+ if (!cpm) {
+ return [];
+ }
+
+ let host = spec.getBidderHost(bidObj);
+
+ const bidResponse = {
+ requestId: bidObj.bidId,
+ cpm: cpm,
+ width: adData.w,
+ height: adData.h,
+ creativeId: bidObj.params.placementId,
+ currency: 'EUR',
+ netRevenue: true,
+ ttl: 300,
+ meta: {
+ advertiserDomains: bidObj && bidObj.adomain ? bidObj.adomain : []
+ }
+ };
+
+ if ('mediaTypes' in bidObj && 'native' in bidObj.mediaTypes) {
+ bidResponse.native = {
+ title: adData.title,
+ body: adData.body,
+ cta: adData.cta,
+ image: { url: adData.image },
+ clickUrl: adData.click,
+ impressionTrackers: [adData.view]
+ };
+ bidResponse.mediaType = NATIVE;
+ } else {
+ let adm = '' + adData.adm;
+ bidResponse.ad = adm;
+ bidResponse.mediaType = BANNER;
+ }
+
+ bidResponses.push(bidResponse);
+ return bidResponses;
+ },
+ getBidderHost: function (bid) {
+ if (bid.bidder === 'adspirit') {
+ return utils.getBidIdParameter('host', bid.params);
+ }
+ if (bid.bidder === 'twiago') {
+ return 'a.twiago.com';
+ }
+ return null;
+ },
+
+ genAdConId: function (bid) {
+ return bid.bidder + Math.round(Math.random() * 100000);
+ }
+};
+
+registerBidder(spec);
diff --git a/modules/adspiritBidAdapter.md b/modules/adspiritBidAdapter.md
new file mode 100644
index 00000000000..698ed9b4a0e
--- /dev/null
+++ b/modules/adspiritBidAdapter.md
@@ -0,0 +1,66 @@
+ # Overview
+
+ ```
+Module Name: Adspirit Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: prebid@adspirit.de
+
+```
+# Description
+
+Connects to Adspirit exchange for bids.
+
+Each adunit with `adspirit` adapter has to have `placementId` and `host`.
+
+
+### Supported Features;
+
+1. Media Types: Banner & native
+2. Multi-format: adUnits
+3. Schain module
+4. Advertiser domains
+
+
+## Sample Banner Ad Unit
+ ```javascript
+ var adUnits = [
+ {
+ code: 'display-div',
+
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]] //a display size
+ }
+ },
+
+ bids: [
+ {
+ bidder: "adspirit",
+ params: {
+ placementId: '7', //Please enter your placementID
+ host: 'test.adspirit.de' //your host details from Adspirit
+ }
+ }
+ ]
+ }
+ ];
+
+```
+
+
+### Privacy Policies
+
+General Data Protection Regulation(GDPR) is supported by default.
+
+Complete information on this URL-- https://support.adspirit.de/hc/en-us/categories/115000453312-General
+
+
+### CMP (Consent Management Provider)
+CMP stands for Consent Management Provider. In simple terms, this is a service provider that obtains and processes the consent of the user, makes it available to the advertisers and, if necessary, logs it for later control. We recommend using a provider with IAB certification or CMP based on the IAB CMP Framework. A list of IAB CMPs can be found at https://iabeurope.eu/cmp-list/. AdSpirit recommends the use of www.consentmanager.de .
+
+### List of functions that require consent
+
+Please visit our page- https://support.adspirit.de/hc/en-us/articles/360014631659-List-of-functions-that-require-consent
+
+
+
diff --git a/modules/adstirBidAdapter.js b/modules/adstirBidAdapter.js
index 4b22d568785..a0c67ddac7e 100644
--- a/modules/adstirBidAdapter.js
+++ b/modules/adstirBidAdapter.js
@@ -36,6 +36,7 @@ export const spec = {
topurl: config.getConfig('pageUrl') ? false : bidderRequest.refererInfo.reachedTop,
},
sua,
+ user: utils.deepAccess(r, 'ortb2.user', null),
gdpr: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies', false),
usp: (bidderRequest.uspConsent || '1---') !== '1---',
eids: utils.deepAccess(r, 'userIdAsEids', []),
diff --git a/modules/adtelligentBidAdapter.js b/modules/adtelligentBidAdapter.js
index cadba499b5c..a95b9ed5652 100644
--- a/modules/adtelligentBidAdapter.js
+++ b/modules/adtelligentBidAdapter.js
@@ -9,6 +9,7 @@ import {chunk} from '../libraries/chunk/chunk.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
*/
const subdomainSuffixes = ['', 1, 2];
@@ -119,7 +120,7 @@ export const spec = {
/**
* Unpack the response from the server into a list of bids
* @param serverResponse
- * @param bidderRequest
+ * @param adapterRequest
* @return {Bid[]} An array of bids which were nested inside the server
*/
interpretResponse: function (serverResponse, { adapterRequest }) {
diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js
index 9bc24b11ac3..ad1c0af039e 100644
--- a/modules/adyoulikeBidAdapter.js
+++ b/modules/adyoulikeBidAdapter.js
@@ -8,6 +8,7 @@ import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
*/
const VERSION = '1.0';
@@ -62,7 +63,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {bidRequests} - bidRequests.bids[] is an array of AdUnits and bids
+ * @param {BidRequest} bidRequests is an array of AdUnits and bids
+ * @param {BidderRequest} bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (bidRequests, bidderRequest) {
diff --git a/modules/airgridRtdProvider.js b/modules/airgridRtdProvider.js
index 2184544807e..079628c88fc 100644
--- a/modules/airgridRtdProvider.js
+++ b/modules/airgridRtdProvider.js
@@ -105,7 +105,7 @@ function init(rtdConfig, userConsent) {
/**
* Real-time data retrieval from AirGrid
- * @param {Object} reqBidsConfigObj
+ * @param {Object} bidConfig
* @param {function} onDone
* @param {Object} rtdConfig
* @param {Object} userConsent
diff --git a/modules/akamaiDapRtdProvider.js b/modules/akamaiDapRtdProvider.js
index f0bb7eb3a6c..0bd53b2a91f 100644
--- a/modules/akamaiDapRtdProvider.js
+++ b/modules/akamaiDapRtdProvider.js
@@ -12,6 +12,10 @@ import {isPlainObject, mergeDeep, logMessage, logInfo, logError} from '../src/ut
import { loadExternalScript } from '../src/adloader.js';
import {MODULE_TYPE_RTD} from '../src/activities/modules.js';
+/**
+ * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
+ */
+
const MODULE_NAME = 'realTimeData';
const SUBMODULE_NAME = 'dap';
const MODULE_CODE = 'akamaidap';
@@ -44,9 +48,8 @@ function mergeLazy(target, source) {
/**
* Add real-time data & merge segments.
- * @param {Object} ortb2 destionation object to merge RTD into
+ * @param {Object} ortb2 destination object to merge RTD into
* @param {Object} rtd
- * @param {Object} rtdConfig
*/
export function addRealTimeData(ortb2, rtd) {
logInfo('DEBUG(addRealTimeData) - ENTER');
@@ -60,7 +63,7 @@ export function addRealTimeData(ortb2, rtd) {
/**
* Real-time data retrieval from Audigent
- * @param {Object} reqBidsConfigObj
+ * @param {Object} bidConfig
* @param {function} onDone
* @param {Object} rtdConfig
* @param {Object} userConsent
diff --git a/modules/apacdexBidAdapter.js b/modules/apacdexBidAdapter.js
index 834df134c2e..dadbdb72e95 100644
--- a/modules/apacdexBidAdapter.js
+++ b/modules/apacdexBidAdapter.js
@@ -327,7 +327,7 @@ export function validateGeoObject(geo) {
* Get bid floor from Price Floors Module
*
* @param {Object} bid
- * @returns {float||null}
+ * @returns {?number}
*/
function getBidFloor(bid) {
if (!isFn(bid.getFloor)) {
diff --git a/modules/appierBidAdapter.js b/modules/appierBidAdapter.js
index fa314f0bd5f..cf89aeefffa 100644
--- a/modules/appierBidAdapter.js
+++ b/modules/appierBidAdapter.js
@@ -37,7 +37,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {bidRequests[]} - an array of bids
+ * @param {object} bidRequests - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (bidRequests, bidderRequest) {
diff --git a/modules/asoBidAdapter.js b/modules/asoBidAdapter.js
index 704cffefb39..a4a6c78566e 100644
--- a/modules/asoBidAdapter.js
+++ b/modules/asoBidAdapter.js
@@ -1,32 +1,20 @@
-import {
- _each,
- deepAccess,
- deepSetValue,
- getDNT,
- inIframe,
- isArray,
- isFn,
- logWarn,
- parseSizesInput
-} from '../src/utils.js';
-import { registerBidder } from '../src/adapters/bidderFactory.js';
-import { config } from '../src/config.js';
-import { BANNER, VIDEO } from '../src/mediaTypes.js';
-import { Renderer } from '../src/Renderer.js';
-import { parseDomain } from '../src/refererDetection.js';
+import {deepAccess, deepSetValue} from '../src/utils.js';
+import {registerBidder} from '../src/adapters/bidderFactory.js';
import {tryAppendQueryString} from '../libraries/urlUtils/urlUtils.js';
+import {ortbConverter} from '../libraries/ortbConverter/converter.js';
+import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
const BIDDER_CODE = 'aso';
const DEFAULT_SERVER_URL = 'https://srv.aso1.net';
const DEFAULT_SERVER_PATH = '/prebid/bidder';
-const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
-const VERSION = '$prebid.version$_1.1';
+const DEFAULT_CURRENCY = 'USD';
+const VERSION = '$prebid.version$_2.0';
const TTL = 300;
export const spec = {
code: BIDDER_CODE,
- supportedMediaTypes: [BANNER, VIDEO],
+ supportedMediaTypes: [BANNER, VIDEO, NATIVE],
aliases: [
{code: 'bcmint'},
{code: 'bidgency'}
@@ -36,91 +24,30 @@ export const spec = {
return !!bid.params && !!bid.params.zone;
},
- buildRequests: (validBidRequests, bidderRequest) => {
- let serverRequests = [];
+ buildRequests: (bidRequests, bidderRequest) => {
+ let requests = [];
- _each(validBidRequests, bidRequest => {
- const payload = createBasePayload(bidRequest, bidderRequest);
-
- const bannerParams = deepAccess(bidRequest, 'mediaTypes.banner');
- const videoParams = deepAccess(bidRequest, 'mediaTypes.video');
-
- let imp;
-
- if (bannerParams && videoParams) {
- logWarn('Please note, multiple mediaTypes are not supported. The only banner will be used.')
- }
-
- if (bannerParams) {
- imp = createBannerImp(bidRequest, bannerParams)
- } else if (videoParams) {
- imp = createVideoImp(bidRequest, videoParams)
- }
-
- if (imp) {
- payload.imp.push(imp);
- } else {
- return;
- }
-
- serverRequests.push({
+ bidRequests.forEach(bid => {
+ const data = converter.toORTB({bidRequests: [bid], bidderRequest});
+ requests.push({
method: 'POST',
- url: getEndpoint(bidRequest),
- data: payload,
+ url: getEndpoint(bid),
+ data,
options: {
withCredentials: true,
crossOrigin: true
},
- bidRequest: bidRequest
- });
+ bidderRequest
+ })
});
-
- return serverRequests;
+ return requests;
},
- interpretResponse: (serverResponse, {bidRequest}) => {
- const response = serverResponse && serverResponse.body;
-
- if (!response) {
- return [];
- }
-
- const serverBids = response.seatbid.reduce((acc, seatBid) => acc.concat(seatBid.bid), []);
- const serverBid = serverBids[0];
-
- let bids = [];
-
- const bid = {
- requestId: serverBid.impid,
- cpm: serverBid.price,
- width: serverBid.w,
- height: serverBid.h,
- ttl: TTL,
- creativeId: serverBid.crid,
- netRevenue: true,
- currency: response.cur,
- mediaType: bidRequest.mediaType,
- meta: {
- mediaType: bidRequest.mediaType,
- advertiserDomains: serverBid.adomain ? serverBid.adomain : []
- }
- };
-
- if (bid.mediaType === BANNER) {
- bid.ad = serverBid.adm;
- } else if (bid.mediaType === VIDEO) {
- bid.vastXml = serverBid.adm;
- if (deepAccess(bidRequest, 'mediaTypes.video.context') === 'outstream') {
- bid.adResponse = {
- content: bid.vastXml,
- };
- bid.renderer = createRenderer(bidRequest, OUTSTREAM_RENDERER_URL);
- }
+ interpretResponse: (response, request) => {
+ if (response.body) {
+ return converter.fromORTB({response: response.body, request: request.data}).bids;
}
-
- bids.push(bid);
-
- return bids;
+ return [];
},
getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) {
@@ -141,16 +68,25 @@ export const spec = {
query = tryAppendQueryString(query, 'us_privacy', uspConsent);
}
- _each(serverResponses, resp => {
+ if (query.slice(-1) === '&') {
+ query = query.slice(0, -1);
+ }
+
+ serverResponses.forEach(resp => {
const userSyncs = deepAccess(resp, 'body.ext.user_syncs');
if (!userSyncs) {
return;
}
- _each(userSyncs, us => {
+ userSyncs.forEach(us => {
+ let url = us.url;
+ if (query) {
+ url = url + (url.indexOf('?') === -1 ? '?' : '&') + query;
+ }
+
urls.push({
type: us.type,
- url: us.url + (query ? '?' + query : '')
+ url: url
});
});
});
@@ -160,123 +96,50 @@ export const spec = {
}
};
-function outstreamRender(bid) {
- bid.renderer.push(() => {
- window.ANOutstreamVideo.renderAd({
- sizes: [bid.width, bid.height],
- targetId: bid.adUnitCode,
- adResponse: bid.adResponse,
- rendererOptions: bid.renderer.getConfig()
- });
- });
-}
-
-function createRenderer(bid, url) {
- const renderer = Renderer.install({
- id: bid.bidId,
- url: url,
- loaded: false,
- config: deepAccess(bid, 'renderer.options'),
- adUnitCode: bid.adUnitCode
- });
- renderer.setRender(outstreamRender);
- return renderer;
-}
-
-function getUrlsInfo(bidderRequest) {
- const {page, domain, ref} = bidderRequest.refererInfo;
- return {
- // TODO: do the fallbacks make sense here?
- page: page || bidderRequest.refererInfo?.topmostLocation,
- referrer: ref || '',
- domain: domain || parseDomain(bidderRequest?.refererInfo?.topmostLocation)
- }
-}
-
-function getSize(paramSizes) {
- const parsedSizes = parseSizesInput(paramSizes);
- const sizes = parsedSizes.map(size => {
- const [width, height] = size.split('x');
- const w = parseInt(width, 10);
- const h = parseInt(height, 10);
- return {w, h};
- });
-
- return sizes[0] || null;
-}
-
-function getBidFloor(bidRequest, size) {
- if (!isFn(bidRequest.getFloor)) {
- return null;
- }
-
- const bidFloor = bidRequest.getFloor({
- mediaType: bidRequest.mediaType,
- size: size ? [size.w, size.h] : '*'
- });
-
- if (!isNaN(bidFloor.floor)) {
- return bidFloor;
- }
-
- return null;
-}
-
-function createBaseImp(bidRequest, size) {
- const imp = {
- id: bidRequest.bidId,
- tagid: bidRequest.adUnitCode,
- secure: 1
- };
-
- const bidFloor = getBidFloor(bidRequest, size);
- if (bidFloor !== null) {
- imp.bidfloor = bidFloor.floor;
- imp.bidfloorcur = bidFloor.currency;
- }
+const converter = ortbConverter({
+ context: {
+ netRevenue: true,
+ ttl: TTL
+ },
- return imp;
-}
+ imp(buildImp, bidRequest, context) {
+ const imp = buildImp(bidRequest, context);
-function createBannerImp(bidRequest, bannerParams) {
- bidRequest.mediaType = BANNER;
+ imp.tagid = bidRequest.adUnitCode;
+ imp.secure = Number(window.location.protocol === 'https:');
+ return imp;
+ },
- const size = getSize(bannerParams.sizes);
- const imp = createBaseImp(bidRequest, size);
+ request(buildRequest, imps, bidderRequest, context) {
+ const request = buildRequest(imps, bidderRequest, context);
- imp.banner = {
- w: size.w,
- h: size.h,
- topframe: inIframe() ? 0 : 1
- }
+ if (bidderRequest.gdprConsent) {
+ const consentsIds = getConsentsIds(bidderRequest.gdprConsent);
+ if (consentsIds) {
+ deepSetValue(request, 'user.ext.consents', consentsIds);
+ }
+ }
- return imp;
-}
+ if (!request.cur) {
+ request.cur = [DEFAULT_CURRENCY];
+ }
-function createVideoImp(bidRequest, videoParams) {
- bidRequest.mediaType = VIDEO;
- const size = getSize(videoParams.playerSize);
- const imp = createBaseImp(bidRequest, size);
+ return request;
+ },
- imp.video = {
- mimes: videoParams.mimes,
- minduration: videoParams.minduration,
- startdelay: videoParams.startdelay,
- linearity: videoParams.linearity,
- maxduration: videoParams.maxduration,
- skip: videoParams.skip,
- protocols: videoParams.protocols,
- skipmin: videoParams.skipmin,
- api: videoParams.api
- }
+ bidResponse(buildBidResponse, bid, context) {
+ context.mediaType = deepAccess(bid, 'ext.prebid.type');
+ return buildBidResponse(bid, context);
+ },
- if (size) {
- imp.video.w = size.w;
- imp.video.h = size.h;
+ overrides: {
+ request: {
+ // We don't need extra data
+ gdprAddtlConsent(setAddtlConsent, ortbRequest, bidderRequest) {
+ }
+ }
}
-
- return imp;
-}
+});
function getEndpoint(bidRequest) {
const serverUrl = bidRequest.params.server || DEFAULT_SERVER_URL;
@@ -287,7 +150,7 @@ function getConsentsIds(gdprConsent) {
const consents = deepAccess(gdprConsent, 'vendorData.purpose.consents', []);
let consentsIds = [];
- Object.keys(consents).forEach(function (key) {
+ Object.keys(consents).forEach(key => {
if (consents[key] === true) {
consentsIds.push(key);
}
@@ -296,61 +159,4 @@ function getConsentsIds(gdprConsent) {
return consentsIds.join(',');
}
-function createBasePayload(bidRequest, bidderRequest) {
- const urlsInfo = getUrlsInfo(bidderRequest);
-
- const payload = {
- id: bidRequest.bidId,
- at: 1,
- tmax: bidderRequest.timeout,
- site: {
- id: urlsInfo.domain,
- domain: urlsInfo.domain,
- page: urlsInfo.page,
- ref: urlsInfo.referrer
- },
- device: {
- dnt: getDNT() ? 1 : 0,
- h: window.innerHeight,
- w: window.innerWidth,
- },
- imp: [],
- ext: {},
- user: {}
- };
-
- if (bidRequest.params.attr) {
- deepSetValue(payload, 'site.ext.attr', bidRequest.params.attr);
- }
-
- if (bidderRequest.gdprConsent) {
- deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
- const consentsIds = getConsentsIds(bidderRequest.gdprConsent);
- if (consentsIds) {
- deepSetValue(payload, 'user.ext.consents', consentsIds);
- }
- deepSetValue(payload, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies & 1);
- }
-
- if (bidderRequest.uspConsent) {
- deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent);
- }
-
- if (config.getConfig('coppa')) {
- deepSetValue(payload, 'regs.coppa', 1);
- }
-
- const eids = deepAccess(bidRequest, 'userIdAsEids');
- if (eids && eids.length) {
- deepSetValue(payload, 'user.ext.eids', eids);
- }
-
- const schainData = deepAccess(bidRequest, 'schain.nodes');
- if (isArray(schainData) && schainData.length > 0) {
- deepSetValue(payload, 'source.ext.schain', bidRequest.schain);
- }
-
- return payload;
-}
-
registerBidder(spec);
diff --git a/modules/asoBidAdapter.md b/modules/asoBidAdapter.md
index f187389c5b5..ebf5cfd4614 100644
--- a/modules/asoBidAdapter.md
+++ b/modules/asoBidAdapter.md
@@ -17,7 +17,6 @@ For more information, please visit [Adserver.Online](https://adserver.online).
| Name | Scope | Description | Example | Type |
|-----------|----------|-------------------------|------------------------|------------|
| `zone` | required | Zone ID | `73815` | `Integer` |
-| `attr` | optional | Custom targeting params | `{foo: ["a", "b"]}` | `Object` |
| `server` | optional | Custom bidder endpoint | `https://endpoint.url` | `String` |
# Test parameters for banner
@@ -49,6 +48,9 @@ var videoAdUnit = [
code: 'video1',
mediaTypes: {
video: {
+ mimes: [
+ "video/mp4"
+ ],
playerSize: [[640, 480]],
context: 'instream' // or 'outstream'
}
@@ -69,7 +71,6 @@ The Adserver.Online Bid Adapter expects Prebid Cache (for video) to be enabled.
```
pbjs.setConfig({
- usePrebidCache: true,
cache: {
url: 'https://prebid.adnxs.com/pbc/v1/cache'
}
diff --git a/modules/astraoneBidAdapter.js b/modules/astraoneBidAdapter.js
index 9645b8e68bd..216257fb7bc 100644
--- a/modules/astraoneBidAdapter.js
+++ b/modules/astraoneBidAdapter.js
@@ -6,6 +6,7 @@ import { BANNER } from '../src/mediaTypes.js'
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
*/
const BIDDER_CODE = 'astraone';
@@ -100,7 +101,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests(validBidRequests, bidderRequest) {
diff --git a/modules/automatadAnalyticsAdapter.js b/modules/automatadAnalyticsAdapter.js
index 7d7bd8cb34c..436418e7597 100644
--- a/modules/automatadAnalyticsAdapter.js
+++ b/modules/automatadAnalyticsAdapter.js
@@ -14,7 +14,7 @@ import { config } from '../src/config.js'
const ADAPTER_CODE = 'automatadAnalytics'
const trialCountMilsMapping = [1500, 3000, 5000, 10000];
-var isLoggingEnabled; var queuePointer = 0; var retryCount = 0; var timer = null; var __atmtdAnalyticsQueue = [];
+var isLoggingEnabled; var queuePointer = 0; var retryCount = 0; var timer = null; var __atmtdAnalyticsQueue = []; var qBeingUsed; var qTraversalComplete;
const prettyLog = (level, text, isGroup = false, cb = () => {}) => {
if (self.isLoggingEnabled === undefined) {
@@ -134,6 +134,9 @@ const processEvents = () => {
if (trialCountMilsMapping[self.retryCount]) self.prettyLog('warn', `Adapter failed to process event as aggregator has not loaded. Retrying in ${trialCountMilsMapping[self.retryCount]}ms ...`);
setTimeout(self.processEvents, trialCountMilsMapping[self.retryCount])
self.retryCount = self.retryCount + 1
+ } else {
+ self.qBeingUsed = false
+ self.qTraversalComplete = true
}
}
@@ -142,22 +145,18 @@ const addGPTHandlers = () => {
googletag.cmd = googletag.cmd || []
googletag.cmd.push(() => {
googletag.pubads().addEventListener('slotRenderEnded', (event) => {
- if (window.atmtdAnalytics && window.atmtdAnalytics.slotRenderEndedGPTHandler) {
- if (window.__atmtdAggregatorFirstAuctionInitialized === true) {
- window.atmtdAnalytics.slotRenderEndedGPTHandler(event)
- return;
- }
+ if (window.atmtdAnalytics && window.atmtdAnalytics.slotRenderEndedGPTHandler && !self.qBeingUsed) {
+ window.atmtdAnalytics.slotRenderEndedGPTHandler(event)
+ return;
}
self.__atmtdAnalyticsQueue.push(['slotRenderEnded', event])
self.prettyLog(`warn`, `Aggregator not initialised at auctionInit, exiting slotRenderEnded handler and pushing to que instead`)
})
googletag.pubads().addEventListener('impressionViewable', (event) => {
- if (window.atmtdAnalytics && window.atmtdAnalytics.impressionViewableHandler) {
- if (window.__atmtdAggregatorFirstAuctionInitialized === true) {
- window.atmtdAnalytics.impressionViewableHandler(event)
- return;
- }
+ if (window.atmtdAnalytics && window.atmtdAnalytics.impressionViewableHandler && !self.qBeingUsed) {
+ window.atmtdAnalytics.impressionViewableHandler(event)
+ return;
}
self.__atmtdAnalyticsQueue.push(['impressionViewable', event])
self.prettyLog(`warn`, `Aggregator not initialised at auctionInit, exiting impressionViewable handler and pushing to que instead`)
@@ -167,6 +166,7 @@ const addGPTHandlers = () => {
const initializeQueue = () => {
self.__atmtdAnalyticsQueue.push = (args) => {
+ self.qBeingUsed = true
Array.prototype.push.apply(self.__atmtdAnalyticsQueue, [args]);
if (timer) {
clearTimeout(timer);
@@ -196,9 +196,10 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
},
track({eventType, args}) {
+ const shouldNotPushToQueue = !self.qBeingUsed
switch (eventType) {
case CONSTANTS.EVENTS.AUCTION_INIT:
- if (window.atmtdAnalytics && window.atmtdAnalytics.auctionInitHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.auctionInitHandler && shouldNotPushToQueue) {
self.prettyLog('status', 'Aggregator loaded, initialising auction through handlers');
window.atmtdAnalytics.auctionInitHandler(args);
} else {
@@ -207,7 +208,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BID_REQUESTED:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidRequestedHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidRequestedHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidRequestedHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -215,7 +216,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BID_REJECTED:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidRejectedHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidRejectedHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidRejectedHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -223,7 +224,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BID_RESPONSE:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidResponseHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidResponseHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidResponseHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -231,7 +232,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BIDDER_DONE:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidderDoneHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidderDoneHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidderDoneHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -239,7 +240,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BID_WON:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidWonHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidWonHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidWonHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -247,7 +248,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.NO_BID:
- if (window.atmtdAnalytics && window.atmtdAnalytics.noBidHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.noBidHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.noBidHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -255,7 +256,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.AUCTION_DEBUG:
- if (window.atmtdAnalytics && window.atmtdAnalytics.auctionDebugHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.auctionDebugHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.auctionDebugHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -263,7 +264,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, {
}
break;
case CONSTANTS.EVENTS.BID_TIMEOUT:
- if (window.atmtdAnalytics && window.atmtdAnalytics.bidderTimeoutHandler) {
+ if (window.atmtdAnalytics && window.atmtdAnalytics.bidderTimeoutHandler && shouldNotPushToQueue) {
window.atmtdAnalytics.bidderTimeoutHandler(args);
} else {
self.prettyLog('warn', `Aggregator not loaded, pushing ${eventType} to que instead ...`);
@@ -304,7 +305,7 @@ atmtdAdapter.enableAnalytics = function (configuration) {
atmtdAdapter.originEnableAnalytics(configuration)
};
-/// /////////// ADAPTER REGISTRATION //////////////
+/// /////////// ADAPTER REGISTRATION /////////////
adapterManager.registerAnalyticsAdapter({
adapter: atmtdAdapter,
@@ -319,7 +320,15 @@ export var self = {
prettyLog,
queuePointer,
retryCount,
- isLoggingEnabled
+ isLoggingEnabled,
+ qBeingUsed,
+ qTraversalComplete
+}
+
+window.__atmtdAnalyticsGlobalObject = {
+ q: self.__atmtdAnalyticsQueue,
+ qBeingUsed: self.qBeingUsed,
+ qTraversalComplete: self.qTraversalComplete
}
export default atmtdAdapter;
diff --git a/modules/azerionedgeRtdProvider.js b/modules/azerionedgeRtdProvider.js
new file mode 100644
index 00000000000..a162ce074aa
--- /dev/null
+++ b/modules/azerionedgeRtdProvider.js
@@ -0,0 +1,143 @@
+/**
+ * This module adds the Azerion provider to the real time data module of prebid.
+ *
+ * The {@link module:modules/realTimeData} module is required
+ * @module modules/azerionedgeRtdProvider
+ * @requires module:modules/realTimeData
+ */
+import { submodule } from '../src/hook.js';
+import { mergeDeep } from '../src/utils.js';
+import { getStorageManager } from '../src/storageManager.js';
+import { loadExternalScript } from '../src/adloader.js';
+import { MODULE_TYPE_RTD } from '../src/activities/modules.js';
+
+/**
+ * @typedef {import('./rtdModule/index.js').RtdSubmodule} RtdSubmodule
+ */
+
+const REAL_TIME_MODULE = 'realTimeData';
+const SUBREAL_TIME_MODULE = 'azerionedge';
+export const STORAGE_KEY = 'ht-pa-v1-a';
+
+export const storage = getStorageManager({
+ moduleType: MODULE_TYPE_RTD,
+ moduleName: SUBREAL_TIME_MODULE,
+});
+
+/**
+ * Get script url to load
+ *
+ * @param {Object} config
+ *
+ * @return {String}
+ */
+function getScriptURL(config) {
+ const VERSION = 'v1';
+ const key = config.params?.key;
+ const publisherPath = key ? `${key}/` : '';
+ return `https://edge.hyth.io/js/${VERSION}/${publisherPath}azerion-edge.min.js`;
+}
+
+/**
+ * Attach script tag to DOM
+ *
+ * @param {Object} config
+ *
+ * @return {void}
+ */
+export function attachScript(config) {
+ const script = getScriptURL(config);
+ loadExternalScript(script, SUBREAL_TIME_MODULE, () => {
+ if (typeof window.azerionPublisherAudiences === 'function') {
+ window.azerionPublisherAudiences(config.params?.process || {});
+ }
+ });
+}
+
+/**
+ * Fetch audiences info from localStorage.
+ *
+ * @return {Array} Audience ids.
+ */
+export function getAudiences() {
+ try {
+ const data = storage.getDataFromLocalStorage(STORAGE_KEY);
+ return JSON.parse(data).map(({ id }) => id);
+ } catch (_) {
+ return [];
+ }
+}
+
+/**
+ * Pass audience data to configured bidders, using ORTB2
+ *
+ * @param {Object} reqBidsConfigObj
+ * @param {Object} config
+ * @param {Array} audiences
+ *
+ * @return {void}
+ */
+export function setAudiencesToBidders(reqBidsConfigObj, config, audiences) {
+ const defaultBidders = ['improvedigital'];
+ const bidders = config.params?.bidders || defaultBidders;
+ bidders.forEach((bidderCode) =>
+ mergeDeep(reqBidsConfigObj.ortb2Fragments.bidder, {
+ [bidderCode]: {
+ user: {
+ data: [
+ {
+ name: 'azerionedge',
+ ext: { segtax: 4 },
+ segment: audiences.map((id) => ({ id })),
+ },
+ ],
+ },
+ },
+ })
+ );
+}
+
+/**
+ * Module initialisation.
+ *
+ * @param {Object} config
+ * @param {Object} userConsent
+ *
+ * @return {boolean}
+ */
+function init(config, userConsent) {
+ attachScript(config);
+ return true;
+}
+
+/**
+ * Real-time user audiences retrieval
+ *
+ * @param {Object} reqBidsConfigObj
+ * @param {function} callback
+ * @param {Object} config
+ * @param {Object} userConsent
+ *
+ * @return {void}
+ */
+export function getBidRequestData(
+ reqBidsConfigObj,
+ callback,
+ config,
+ userConsent
+) {
+ const audiences = getAudiences();
+ if (audiences.length > 0) {
+ setAudiencesToBidders(reqBidsConfigObj, config, audiences);
+ }
+ callback();
+}
+
+/** @type {RtdSubmodule} */
+export const azerionedgeSubmodule = {
+ name: SUBREAL_TIME_MODULE,
+ init: init,
+ getBidRequestData: getBidRequestData,
+};
+
+submodule(REAL_TIME_MODULE, azerionedgeSubmodule);
diff --git a/modules/azerionedgeRtdProvider.md b/modules/azerionedgeRtdProvider.md
new file mode 100644
index 00000000000..2849bef3f63
--- /dev/null
+++ b/modules/azerionedgeRtdProvider.md
@@ -0,0 +1,112 @@
+---
+layout: page_v2
+title: azerion edge RTD Provider
+display_name: Azerion Edge RTD Provider
+description: Client-side contextual cookieless audiences.
+page_type: module
+module_type: rtd
+module_code: azerionedgeRtdProvider
+enable_download: true
+vendor_specific: true
+sidebarType: 1
+---
+
+# Azerion Edge RTD Provider
+
+Client-side contextual cookieless audiences.
+
+Azerion Edge RTD module helps publishers to capture users' interest
+audiences on their site, and attach these into the bid request.
+
+Maintainer: [azerion.com](https://www.azerion.com/)
+
+{:.no_toc}
+
+- TOC
+ {:toc}
+
+## Integration
+
+Compile the Azerion Edge RTD module (`azerionedgeRtdProvider`) into your Prebid build,
+along with the parent RTD Module (`rtdModule`):
+
+```bash
+gulp build --modules=rtdModule,azerionedgeRtdProvider
+```
+
+Set configuration via `pbjs.setConfig`.
+
+```js
+pbjs.setConfig(
+ ...
+ realTimeData: {
+ auctionDelay: 1000,
+ dataProviders: [
+ {
+ name: 'azerionedge',
+ waitForIt: true,
+ params: {
+ key: '',
+ bidders: ['improvedigital'],
+ process: {}
+ }
+ }
+ ]
+ }
+ ...
+}
+```
+
+### Parameter Description
+
+{: .table .table-bordered .table-striped }
+| Name | Type | Description | Notes |
+| :--- | :------- | :------------------ | :--------------- |
+| name | `String` | RTD sub module name | Always "azerionedge" |
+| waitForIt | `Boolean` | Required to ensure that the auction is delayed for the module to respond. | Optional. Defaults to false but recommended to true. |
+| params.key | `String` | Publisher partner specific key | Optional |
+| params.bidders | `Array` | Bidders with which to share segment information | Optional. Defaults to "improvedigital". |
+| params.process | `Object` | Configuration for the Azerion Edge script. | Optional. Defaults to `{}`. |
+
+## Context
+
+As all data collection is on behalf of the publisher and based on the consent the publisher has
+received from the user, this module does not require a TCF vendor configuration. Consent is
+provided to the module when the user gives the relevant permissions on the publisher website.
+
+As Prebid.js utilizes TCF vendor consent for the RTD module to load, the module needs to be labeled
+within the Vendor Exceptions.
+
+### Instructions
+
+If the Prebid GDPR enforcement is enabled, the module should be labeled
+as exception, as shown below:
+
+```js
+[
+ {
+ purpose: 'storage',
+ enforcePurpose: true,
+ enforceVendor: true,
+ vendorExceptions: ["azerionedge"]
+ },
+ ...
+]
+```
+
+## Testing
+
+To view an example:
+
+```bash
+gulp serve-fast --modules=rtdModule,azerionedgeRtdProvider
+```
+
+Access [http://localhost:9999/integrationExamples/gpt/azerionedgeRtdProvider_example.html](http://localhost:9999/integrationExamples/gpt/azerionedgeRtdProvider_example.html)
+in your browser.
+
+Run the unit tests:
+
+```bash
+npm test -- --file "test/spec/modules/azerionedgeRtdProvider_spec.js"
+```
diff --git a/modules/beopBidAdapter.js b/modules/beopBidAdapter.js
index 89289654b32..0b2a965448b 100644
--- a/modules/beopBidAdapter.js
+++ b/modules/beopBidAdapter.js
@@ -12,6 +12,12 @@ import {registerBidder} from '../src/adapters/bidderFactory.js';
import {config} from '../src/config.js';
import {getAllOrtbKeywords} from '../libraries/keywords/keywords.js';
+/**
+ * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ */
+
const BIDDER_CODE = 'beop';
const ENDPOINT_URL = 'https://hb.beop.io/bid';
const TCF_VENDOR_ID = 666;
@@ -25,7 +31,7 @@ export const spec = {
/**
* Test if the bid request is valid.
*
- * @param {bid} : The Bid params
+ * @param {Bid} bid The Bid params
* @return boolean true if the bid request is valid (aka contains a valid accountId or networkId and is open for BANNER), false otherwise.
*/
isBidRequestValid: function(bid) {
@@ -41,8 +47,8 @@ export const spec = {
/**
* Create a BeOp server request from a list of BidRequest
*
- * @param {validBidRequests[], ...} : The array of validated bidRequests
- * @param {... , bidderRequest} : Common params for each bidRequests
+ * @param {validBidRequests} validBidRequests The array of validated bidRequests
+ * @param {BidderRequest} bidderRequest Common params for each bidRequests
* @return ServerRequest Info describing the request to the BeOp's server
*/
buildRequests: function(validBidRequests, bidderRequest) {
diff --git a/modules/betweenBidAdapter.js b/modules/betweenBidAdapter.js
index 4a953875d99..d2010f22e1a 100644
--- a/modules/betweenBidAdapter.js
+++ b/modules/betweenBidAdapter.js
@@ -6,6 +6,7 @@ import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
* @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
@@ -31,7 +32,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequest?pbjs_debug=trues[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js
index 6074d1a0e4c..7ae1ccf9217 100644
--- a/modules/bidglassBidAdapter.js
+++ b/modules/bidglassBidAdapter.js
@@ -4,6 +4,8 @@ import {registerBidder} from '../src/adapters/bidderFactory.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
*/
@@ -24,7 +26,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
+ * @param {BidderRequest} bidderRequest request by bidder
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
diff --git a/modules/bliinkBidAdapter.js b/modules/bliinkBidAdapter.js
index debe956d7eb..37c99878d68 100644
--- a/modules/bliinkBidAdapter.js
+++ b/modules/bliinkBidAdapter.js
@@ -153,7 +153,7 @@ export function getDomLoadingDuration() {
}
/**
- * @param bidRequest
+ * @param bidResponse
* @return {({cpm, netRevenue: boolean, requestId, width: number, currency, ttl: number, creativeId, height: number}&{mediaType: string, vastXml})|null}
*/
export const buildBid = (bidResponse) => {
@@ -285,7 +285,6 @@ export const buildRequests = (validBidRequests, bidderRequest) => {
* @description Parse the response (from buildRequests) and generate one or more bid objects.
*
* @param serverResponse
- * @param request
* @return
*/
const interpretResponse = (serverResponse) => {
diff --git a/modules/blueconicRtdProvider.js b/modules/blueconicRtdProvider.js
index 6b10e79b94c..c09fc6ee34c 100644
--- a/modules/blueconicRtdProvider.js
+++ b/modules/blueconicRtdProvider.js
@@ -37,9 +37,8 @@ function parseJson(data) {
/**
* Add real-time data & merge segments.
- * @param {Object} bidConfig
+ * @param {Object} ortb2
* @param {Object} rtd
- * @param {Object} rtdConfig
*/
export function addRealTimeData(ortb2, rtd) {
if (isPlainObject(rtd.ortb2)) {
@@ -82,7 +81,7 @@ export function getRealTimeData(reqBidsConfigObj, onDone, rtdConfig, userConsent
/**
* Module init
* @param {Object} provider
- * @param {Objkect} userConsent
+ * @param {Object} userConsent
* @return {boolean}
*/
function init(provider, userConsent) {
diff --git a/modules/brandmetricsRtdProvider.js b/modules/brandmetricsRtdProvider.js
index 17336baa76c..2d9dcdfdf48 100644
--- a/modules/brandmetricsRtdProvider.js
+++ b/modules/brandmetricsRtdProvider.js
@@ -78,6 +78,7 @@ function checkConsent (userConsent) {
/**
* Add event- listeners to hook in to brandmetrics events
* @param {Object} reqBidsConfigObj
+ * @param {Object} moduleConfig
* @param {function} callback
*/
function processBrandmetricsEvents (reqBidsConfigObj, moduleConfig, callback) {
@@ -114,6 +115,7 @@ function processBrandmetricsEvents (reqBidsConfigObj, moduleConfig, callback) {
/**
* Sets bid targeting of specific bidders
* @param {Object} reqBidsConfigObj
+ * @param {Object} moduleConfig
* @param {string} key Targeting key
* @param {string} val Targeting value
*/
diff --git a/modules/britepoolIdSystem.js b/modules/britepoolIdSystem.js
index 37ace544dc7..dcc365faaac 100644
--- a/modules/britepoolIdSystem.js
+++ b/modules/britepoolIdSystem.js
@@ -38,7 +38,7 @@ export const britepoolIdSubmodule = {
* @function
* @param {SubmoduleConfig} [submoduleConfig]
* @param {ConsentData|undefined} consentData
- * @returns {function(callback:function)}
+ * @returns {function}
*/
getId(submoduleConfig, consentData) {
const submoduleConfigParams = (submoduleConfig && submoduleConfig.params) || {};
diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js
index 5281274616a..ab3db2a5d20 100644
--- a/modules/browsiRtdProvider.js
+++ b/modules/browsiRtdProvider.js
@@ -191,7 +191,6 @@ function getAllSlots() {
/**
* get prediction and return valid object for key value set
* @param {number} p
- * @param {string?} keyName
* @return {Object} key:value
*/
function getKVObject(p) {
diff --git a/modules/buzzoolaBidAdapter.js b/modules/buzzoolaBidAdapter.js
index 14a26203484..ae77ee159bc 100644
--- a/modules/buzzoolaBidAdapter.js
+++ b/modules/buzzoolaBidAdapter.js
@@ -53,7 +53,6 @@ export const spec = {
* Unpack the response from the server into a list of bids.
*
* @param {ServerResponse} serverResponse A successful response from the server.
- * @param bidderRequest
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function ({body}, {data}) {
diff --git a/modules/codefuelBidAdapter.js b/modules/codefuelBidAdapter.js
index a289e29bd19..a4accee3ce0 100644
--- a/modules/codefuelBidAdapter.js
+++ b/modules/codefuelBidAdapter.js
@@ -5,6 +5,7 @@ import {BANNER} from '../src/mediaTypes.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
* @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
@@ -32,7 +33,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js
index cc3e452f20c..5fe78ff932d 100644
--- a/modules/colossussspBidAdapter.js
+++ b/modules/colossussspBidAdapter.js
@@ -140,7 +140,7 @@ export const spec = {
groupId: bid.params.group_id,
bidId: bid.bidId,
tid: bid.ortb2Imp?.ext?.tid,
- eids: [],
+ eids: bid.userIdAsEids || [],
floor: {}
};
diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js
index 7524cd4e194..0b840db6c26 100644
--- a/modules/connatixBidAdapter.js
+++ b/modules/connatixBidAdapter.js
@@ -98,6 +98,7 @@ export const spec = {
ortb2: bidderRequest.ortb2,
gdprConsent: bidderRequest.gdprConsent,
uspConsent: bidderRequest.uspConsent,
+ gppConsent: bidderRequest.gppConsent,
refererInfo: bidderRequest.refererInfo,
bidRequests,
};
diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js
index 0618a076193..c1fcac4ae2f 100644
--- a/modules/criteoBidAdapter.js
+++ b/modules/criteoBidAdapter.js
@@ -24,9 +24,6 @@ export const ADAPTER_VERSION = 36;
const BIDDER_CODE = 'criteo';
const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb';
const PROFILE_ID_INLINE = 207;
-const FLEDGE_SELLER_DOMAIN = 'https://grid-mercury.criteo.com';
-const FLEDGE_SELLER_TIMEOUT = 500;
-const FLEDGE_DECISION_LOGIC_URL = 'https://grid-mercury.criteo.com/fledge/decision';
export const PROFILE_ID_PUBLISHERTAG = 185;
export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
const LOG_PREFIX = 'Criteo: ';
@@ -284,53 +281,13 @@ export const spec = {
});
}
- if (isArray(body.ext?.igbid)) {
- const seller = body.ext.seller || FLEDGE_SELLER_DOMAIN;
- const sellerTimeout = body.ext.sellerTimeout || FLEDGE_SELLER_TIMEOUT;
- body.ext.igbid.forEach((igbid) => {
- const perBuyerSignals = {};
- igbid.igbuyer.forEach(buyerItem => {
- perBuyerSignals[buyerItem.origin] = buyerItem.buyerdata;
- });
- const bidRequest = request.bidRequests.find(b => b.bidId === igbid.impid);
- const bidId = bidRequest.bidId;
- let sellerSignals = body.ext.sellerSignals || {};
- if (!sellerSignals.floor && bidRequest.params.bidFloor) {
- sellerSignals.floor = bidRequest.params.bidFloor;
- }
- let perBuyerTimeout = { '*': 50 };
- if (sellerSignals.perBuyerTimeout) {
- for (const buyer in sellerSignals.perBuyerTimeout) {
- perBuyerTimeout[buyer] = sellerSignals.perBuyerTimeout[buyer];
- }
- }
- let perBuyerGroupLimits = { '*': 60 };
- if (sellerSignals.perBuyerGroupLimits) {
- for (const buyer in sellerSignals.perBuyerGroupLimits) {
- perBuyerGroupLimits[buyer] = sellerSignals.perBuyerGroupLimits[buyer];
- }
- }
- if (body?.ext?.sellerSignalsPerImp !== undefined) {
- const sellerSignalsPerImp = body.ext.sellerSignalsPerImp[bidId];
- if (sellerSignalsPerImp !== undefined) {
- sellerSignals = {...sellerSignals, ...sellerSignalsPerImp};
- }
+ if (isArray(body.ext?.igi)) {
+ body.ext.igi.forEach((igi) => {
+ if (isArray(igi?.igs)) {
+ igi.igs.forEach((igs) => {
+ fledgeAuctionConfigs.push(igs);
+ });
}
- fledgeAuctionConfigs.push({
- bidId,
- config: {
- seller,
- sellerSignals,
- sellerTimeout,
- perBuyerSignals,
- perBuyerTimeout,
- perBuyerGroupLimits,
- auctionSignals: {},
- decisionLogicUrl: FLEDGE_DECISION_LOGIC_URL,
- interestGroupBuyers: Object.keys(perBuyerSignals),
- sellerCurrency: sellerSignals.currency || '???',
- },
- });
});
}
diff --git a/modules/cwireBidAdapter.js b/modules/cwireBidAdapter.js
index d36948d162d..f878be5f66a 100644
--- a/modules/cwireBidAdapter.js
+++ b/modules/cwireBidAdapter.js
@@ -16,6 +16,7 @@ const CWID_KEY = 'cw_cwid';
export const BID_ENDPOINT = 'https://prebid.cwi.re/v1/bid';
export const EVENT_ENDPOINT = 'https://prebid.cwi.re/v1/event';
+export const GVL_ID = 1081;
/**
* Allows limiting ad impressions per site render. Unique per prebid instance ID.
@@ -140,6 +141,7 @@ function getCwExtension() {
export const spec = {
code: BIDDER_CODE,
+ gvlid: GVL_ID,
supportedMediaTypes: [BANNER],
/**
diff --git a/modules/debugging/bidInterceptor.js b/modules/debugging/bidInterceptor.js
index 775f8fc3da2..3afaacaeb81 100644
--- a/modules/debugging/bidInterceptor.js
+++ b/modules/debugging/bidInterceptor.js
@@ -54,8 +54,9 @@ Object.assign(BidInterceptor.prototype, {
return {
no: ruleNo,
match: this.matcher(ruleDef.when, ruleNo),
- replace: this.replacer(ruleDef.then || {}, ruleNo),
+ replace: this.replacer(ruleDef.then, ruleNo),
options: Object.assign({}, this.DEFAULT_RULE_OPTIONS, ruleDef.options),
+ paapi: this.paapiReplacer(ruleDef.paapi || [], ruleNo)
}
},
/**
@@ -114,6 +115,10 @@ Object.assign(BidInterceptor.prototype, {
* @return {ReplacerFn}
*/
replacer(replDef, ruleNo) {
+ if (replDef === null) {
+ return () => null
+ }
+ replDef = replDef || {};
let replFn;
if (typeof replDef === 'function') {
replFn = ({args}) => replDef(...args);
@@ -145,6 +150,17 @@ Object.assign(BidInterceptor.prototype, {
return response;
}
},
+
+ paapiReplacer(paapiDef, ruleNo) {
+ if (Array.isArray(paapiDef)) {
+ return () => paapiDef;
+ } else if (typeof paapiDef === 'function') {
+ return paapiDef
+ } else {
+ this.logger.logError(`Invalid 'paapi' definition for debug bid interceptor (in rule #${ruleNo})`);
+ }
+ },
+
responseDefaults(bid) {
return {
requestId: bid.bidId,
@@ -198,11 +214,12 @@ Object.assign(BidInterceptor.prototype, {
* @param {{}[]} bids?
* @param {BidRequest} bidRequest
* @param {function(*)} addBid called once for each mock response
+ * @param addPaapiConfig called once for each mock PAAPI config
* @param {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, done}) {
+ intercept({bids, bidRequest, addBid, addPaapiConfig, done}) {
if (bids == null) {
bids = bidRequest.bids;
}
@@ -211,10 +228,12 @@ Object.assign(BidInterceptor.prototype, {
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:`, match.bid, mockResponse)
+ 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.setTimeout(() => {
- addBid(mockResponse, match.bid);
+ 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 8a4ad7a9545..2fd1731dc4e 100644
--- a/modules/debugging/debugging.js
+++ b/modules/debugging/debugging.js
@@ -99,7 +99,13 @@ function registerBidInterceptor(getHookFn, interceptor) {
export function bidderBidInterceptor(next, interceptBids, spec, bids, bidRequest, ajax, wrapCallback, cbs) {
const done = delayExecution(cbs.onCompletion, 2);
- ({bids, bidRequest} = interceptBids({bids, bidRequest, addBid: cbs.onBid, done}));
+ ({bids, bidRequest} = interceptBids({
+ bids,
+ bidRequest,
+ addBid: cbs.onBid,
+ addPaapiConfig: (config, bidRequest) => cbs.onPaapi({bidId: bidRequest.bidId, config}),
+ done
+ }));
if (bids.length === 0) {
done();
} else {
diff --git a/modules/debugging/pbsInterceptor.js b/modules/debugging/pbsInterceptor.js
index 1ca13eb4927..73df01bf205 100644
--- a/modules/debugging/pbsInterceptor.js
+++ b/modules/debugging/pbsInterceptor.js
@@ -5,7 +5,8 @@ export function makePbsInterceptor({createBid}) {
return function pbsBidInterceptor(next, interceptBids, s2sBidRequest, bidRequests, ajax, {
onResponse,
onError,
- onBid
+ onBid,
+ onFledge,
}) {
let responseArgs;
const done = delayExecution(() => onResponse(...responseArgs), bidRequests.length + 1)
@@ -20,7 +21,19 @@ export function makePbsInterceptor({createBid}) {
})
}
bidRequests = bidRequests
- .map((req) => interceptBids({bidRequest: req, addBid, done}).bidRequest)
+ .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)
if (bidRequests.length > 0) {
diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js
index ad8f5616d44..de2fd3c3a94 100644
--- a/modules/discoveryBidAdapter.js
+++ b/modules/discoveryBidAdapter.js
@@ -65,7 +65,7 @@ const NATIVERET = {
};
/**
- * get page title
+ * get page title111
* @returns {string}
*/
@@ -133,10 +133,11 @@ export const getPmgUID = () => {
let pmgUid = storage.getCookie(COOKIE_KEY_PMGUID);
if (!pmgUid) {
pmgUid = utils.generateUUID();
- try {
- storage.setCookie(COOKIE_KEY_PMGUID, pmgUid, getCurrentTimeToUTCString());
- } catch (e) {}
}
+ // Extend the expiration time of pmguid
+ try {
+ storage.setCookie(COOKIE_KEY_PMGUID, pmgUid, getCurrentTimeToUTCString());
+ } catch (e) {}
return pmgUid;
};
@@ -436,6 +437,7 @@ function getParam(validBidRequests, bidderRequest) {
const page = utils.deepAccess(bidderRequest, 'refererInfo.page');
const referer = utils.deepAccess(bidderRequest, 'refererInfo.ref');
const firstPartyData = bidderRequest.ortb2;
+ const tpData = utils.deepAccess(bidderRequest, 'ortb2.user.data') || undefined;
const topWindow = window.top;
const title = getPageTitle();
const desc = getPageDescription();
@@ -462,6 +464,7 @@ function getParam(validBidRequests, bidderRequest) {
firstPartyData,
ssppid: storage.getCookie(COOKIE_KEY_SSPPID) || undefined,
pmguid: getPmgUID(),
+ tpData,
page: {
title: title ? title.slice(0, 100) : undefined,
desc: desc ? desc.slice(0, 300) : undefined,
diff --git a/modules/dsp_genieeBidAdapter.js b/modules/dsp_genieeBidAdapter.js
index 17865e6793a..57aafd47fc8 100644
--- a/modules/dsp_genieeBidAdapter.js
+++ b/modules/dsp_genieeBidAdapter.js
@@ -3,6 +3,16 @@ import { BANNER } from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { deepAccess, deepSetValue } from '../src/utils.js';
import { config } from '../src/config.js';
+
+/**
+ * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
+ * @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
+ * @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
+ */
+
const BIDDER_CODE = 'dsp_geniee';
const ENDPOINT_URL = 'https://rt.gsspat.jp/prebid_auction';
const ENDPOINT_URL_UNCOMFORTABLE = 'https://rt.gsspat.jp/prebid_uncomfortable';
@@ -44,7 +54,7 @@ export const spec = {
/**
* Determines whether or not the given bid request is valid.
*
- * @param {BidRequest} - The bid params to validate.
+ * @param {BidRequest} _ The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (_) {
@@ -53,8 +63,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
- * @param {bidderRequest} - the master bidRequest object
+ * @param {validBidRequests} validBidRequests - an array of bids
+ * @param {BidderRequest} bidderRequest - the master bidRequest object
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js
index b4490095894..ea47c64094d 100644
--- a/modules/dspxBidAdapter.js
+++ b/modules/dspxBidAdapter.js
@@ -331,8 +331,8 @@ function getBannerSizes(bid) {
/**
* Parse size
- * @param sizes
- * @returns {width: number, h: height}
+ * @param size
+ * @returns {object} sizeObj
*/
function parseSize(size) {
let sizeObj = {}
diff --git a/modules/dxkultureBidAdapter.js b/modules/dxkultureBidAdapter.js
index c167baef6ea..d803c476b6d 100644
--- a/modules/dxkultureBidAdapter.js
+++ b/modules/dxkultureBidAdapter.js
@@ -96,7 +96,7 @@ export const spec = {
/**
* Determines whether or not the given bid request is valid.
*
- * @param {BidRequest} bidRequest The bid params to validate.
+ * @param {BidRequest} bid The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
@@ -269,7 +269,7 @@ function _validateParams(bidRequest) {
/**
* Validates banner bid request. If it is not banner media type returns true.
- * @param {object} bid, bid to validate
+ * @param {BidRequest} bidRequest bid to validate
* @return boolean, true if valid, otherwise false
*/
function _validateBanner(bidRequest) {
@@ -287,7 +287,7 @@ function _validateBanner(bidRequest) {
/**
* Validates video bid request. If it is not video media type returns true.
- * @param {object} bid, bid to validate
+ * @param {BidRequest} bidRequest, bid to validate
* @return boolean, true if valid, otherwise false
*/
function _validateVideo(bidRequest) {
diff --git a/modules/dynamicAdBoostRtdProvider.js b/modules/dynamicAdBoostRtdProvider.js
index fe08795f313..697bd7340d3 100644
--- a/modules/dynamicAdBoostRtdProvider.js
+++ b/modules/dynamicAdBoostRtdProvider.js
@@ -9,6 +9,10 @@ import { loadExternalScript } from '../src/adloader.js';
import { getGlobal } from '../src/prebidGlobal.js';
import { deepAccess, deepSetValue, isEmptyStr } from '../src/utils.js';
+/**
+ * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
+ */
+
const MODULE_NAME = 'dynamicAdBoost';
const SCRIPT_URL = 'https://adxbid.info';
const CLIENT_SUPPORTS_IO = window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype &&
diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js
index e68a932b726..5ee9906b5df 100644
--- a/modules/feedadBidAdapter.js
+++ b/modules/feedadBidAdapter.js
@@ -9,7 +9,7 @@ import {ajax} from '../src/ajax.js';
* @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest
* @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
* @typedef {import('../src/adapters/bidderFactory.js').BidderSpec} BidderSpec
- * @typedef {import('../src/adapters/bidderFactory.js').MediaTypes} MediaTypes
+ * @typedef {import('../src/adapters/bidderFactory.js').MediaType} MediaType
*/
/**
diff --git a/modules/flippBidAdapter.js b/modules/flippBidAdapter.js
index 0708c90ac0d..f9c424d9da5 100644
--- a/modules/flippBidAdapter.js
+++ b/modules/flippBidAdapter.js
@@ -6,6 +6,8 @@ import {getStorageManager} from '../src/storageManager.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
* @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
@@ -105,7 +107,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {BidRequest[]} validBidRequests[] an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
* @param {BidderRequest} bidderRequest master bidRequest object
* @return ServerRequest Info describing the request to the server.
*/
diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js
index f6d97fa7cd8..c0ae55efc89 100644
--- a/modules/fluctBidAdapter.js
+++ b/modules/fluctBidAdapter.js
@@ -4,6 +4,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
* @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
*/
@@ -30,8 +31,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids.
- * @param {bidderRequest} bidderRequest bidder request object.
+ * @param {validBidRequests} validBidRequests an array of bids.
+ * @param {BidderRequest} bidderRequest bidder request object.
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: (validBidRequests, bidderRequest) => {
diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js
index c4653181fd0..e11aa3f8fb7 100644
--- a/modules/freewheel-sspBidAdapter.js
+++ b/modules/freewheel-sspBidAdapter.js
@@ -482,7 +482,7 @@ export const spec = {
* Unpack the response from the server into a list of bids.
*
* @param {*} serverResponse A successful response from the server.
- * @param {object} request: the built request object containing the initial bidRequest.
+ * @param {object} request the built request object containing the initial bidRequest.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function(serverResponse, request) {
diff --git a/modules/geoedgeRtdProvider.js b/modules/geoedgeRtdProvider.js
index a2ed71a898c..0b0d9027c03 100644
--- a/modules/geoedgeRtdProvider.js
+++ b/modules/geoedgeRtdProvider.js
@@ -56,7 +56,7 @@ let preloaded;
/**
* fetches the creative wrapper
- * @param {function} sucess - success callback
+ * @param {function} success - success callback
*/
export function fetchWrapper(success) {
if (wrapperReady) {
diff --git a/modules/getintentBidAdapter.js b/modules/getintentBidAdapter.js
index 7353a1c1f67..a8888893333 100644
--- a/modules/getintentBidAdapter.js
+++ b/modules/getintentBidAdapter.js
@@ -111,8 +111,8 @@ function buildUrl(bid) {
/**
* Builds GI bid request from BidRequest.
*
- * @param {BidRequest} bidRequest.
- * @return {object} GI bid request.
+ * @param {BidRequest} bidRequest
+ * @return {object} GI bid request
*/
function buildGiBidRequest(bidRequest) {
let giBidRequest = {
diff --git a/modules/gjirafaBidAdapter.js b/modules/gjirafaBidAdapter.js
index 9259010ac78..ef19a097062 100644
--- a/modules/gjirafaBidAdapter.js
+++ b/modules/gjirafaBidAdapter.js
@@ -5,6 +5,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
* @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
*/
@@ -33,7 +34,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
+ * @param {BidderRequest} bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
diff --git a/modules/gmosspBidAdapter.js b/modules/gmosspBidAdapter.js
index c4b8cd819e0..d7af51f7312 100644
--- a/modules/gmosspBidAdapter.js
+++ b/modules/gmosspBidAdapter.js
@@ -15,6 +15,7 @@ import {tryAppendQueryString} from '../libraries/urlUtils/urlUtils.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
* @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
* @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
* @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
@@ -41,7 +42,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
+ * @param {BidderRequest} bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
diff --git a/modules/gnetBidAdapter.js b/modules/gnetBidAdapter.js
index 4718438b9bb..1bcc774e351 100644
--- a/modules/gnetBidAdapter.js
+++ b/modules/gnetBidAdapter.js
@@ -7,6 +7,7 @@ import {ajax} from '../src/ajax.js';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
* @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
*/
@@ -31,7 +32,8 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} validBidRequests an array of bids
+ * @param {BidderRequest} bidderRequest
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
diff --git a/modules/growthCodeIdSystem.js b/modules/growthCodeIdSystem.js
index cf72e2e5133..be20ab89130 100644
--- a/modules/growthCodeIdSystem.js
+++ b/modules/growthCodeIdSystem.js
@@ -9,6 +9,12 @@ import { submodule } from '../src/hook.js'
import {getStorageManager} from '../src/storageManager.js';
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
+/**
+ * @typedef {import('../modules/userId/index.js').Submodule} Submodule
+ * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
+ * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
+ */
+
const MODULE_NAME = 'growthCodeId';
const GCID_KEY = 'gcid';
diff --git a/modules/hadronIdSystem.js b/modules/hadronIdSystem.js
index 01b0283d3d1..66cb5624a38 100644
--- a/modules/hadronIdSystem.js
+++ b/modules/hadronIdSystem.js
@@ -25,7 +25,7 @@ const MODULE_NAME = 'hadronId';
const AU_GVLID = 561;
const DEFAULT_HADRON_URL_ENDPOINT = 'https://id.hadron.ad.gt/api/v1/pbhid';
-export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: 'hadron'});
+export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME});
/**
* Param or default.
diff --git a/modules/hypelabBidAdapter.js b/modules/hypelabBidAdapter.js
index a625c7299a6..14a4758bd27 100644
--- a/modules/hypelabBidAdapter.js
+++ b/modules/hypelabBidAdapter.js
@@ -1,6 +1,6 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
-import { generateUUID } from '../src/utils.js';
+import { generateUUID, isFn, isPlainObject } from '../src/utils.js';
import { ajax } from '../src/ajax.js';
export const BIDDER_CODE = 'hypelab';
@@ -12,7 +12,7 @@ export const REPORTING_ROUTE = '';
const PREBID_VERSION = '$prebid.version$';
const PROVIDER_NAME = 'prebid';
-const PROVIDER_VERSION = '0.0.1';
+const PROVIDER_VERSION = '0.0.2';
const url = (route) => ENDPOINT_URL + route;
@@ -38,18 +38,24 @@ function buildRequests(validBidRequests, bidderRequest) {
const uuid = uids[0] ? uids[0] : generateTemporaryUUID();
+ const floor = getBidFloor(request, request.sizes || []);
+
+ const dpr = typeof window != 'undefined' ? window.devicePixelRatio : 1;
+
const payload = {
property_slug: request.params.property_slug,
placement_slug: request.params.placement_slug,
provider_version: PROVIDER_VERSION,
provider_name: PROVIDER_NAME,
- referrer:
+ location:
bidderRequest.refererInfo?.page || typeof window != 'undefined'
? window.location.href
: '',
sdk_version: PREBID_VERSION,
sizes: request.sizes,
wids: [],
+ floor,
+ dpr,
uuid,
bidRequestsCount: request.bidRequestsCount,
bidderRequestsCount: request.bidderRequestsCount,
@@ -79,6 +85,26 @@ function generateTemporaryUUID() {
return 'tmp_' + generateUUID();
}
+function getBidFloor(bid, sizes) {
+ if (!isFn(bid.getFloor)) {
+ return bid.params.bidFloor ? bid.params.bidFloor : null;
+ }
+
+ let floor;
+
+ let floorInfo = bid.getFloor({
+ currency: 'USD',
+ mediaType: 'banner',
+ size: sizes.length === 1 ? sizes[0] : '*'
+ });
+
+ if (isPlainObject(floorInfo) && floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) {
+ floor = parseFloat(floorInfo.floor);
+ }
+
+ return floor;
+}
+
function interpretResponse(serverResponse, bidRequest) {
const { data } = serverResponse.body;
@@ -94,12 +120,12 @@ function interpretResponse(serverResponse, bidRequest) {
creativeId: data.creative_set_slug,
currency: data.currency,
netRevenue: true,
- referrer: bidRequest.data.referrer,
+ referrer: bidRequest.data.location,
ttl: data.ttl,
ad: data.html,
mediaType: serverResponse.body.data.media_type,
meta: {
- advertiserDomains: data.advertiserDomains || [],
+ advertiserDomains: data.advertiser_domains || [],
},
};
diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js
index c585f2fdae0..42f0044edc3 100644
--- a/modules/id5IdSystem.js
+++ b/modules/id5IdSystem.js
@@ -10,6 +10,7 @@ import {
deepSetValue,
isEmpty,
isEmptyStr,
+ isPlainObject,
logError,
logInfo,
logWarn,
@@ -21,8 +22,8 @@ import {getRefererInfo} from '../src/refererDetection.js';
import {getStorageManager} from '../src/storageManager.js';
import {uspDataHandler, gppDataHandler} from '../src/adapterManager.js';
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
-import { GreedyPromise } from '../src/utils/promise.js';
-import { loadExternalScript } from '../src/adloader.js';
+import {GreedyPromise} from '../src/utils/promise.js';
+import {loadExternalScript} from '../src/adloader.js';
/**
* @typedef {import('../modules/userId/index.js').Submodule} Submodule
@@ -39,6 +40,7 @@ export const ID5_PRIVACY_STORAGE_NAME = `${ID5_STORAGE_NAME}_privacy`;
const LOCAL_STORAGE = 'html5';
const LOG_PREFIX = 'User ID - ID5 submodule: ';
const ID5_API_CONFIG_URL = 'https://id5-sync.com/api/config/prebid';
+const ID5_DOMAIN = 'id5-sync.com';
// order the legacy cookie names in reverse priority order so the last
// cookie in the array is the most preferred to use
@@ -146,9 +148,17 @@ export const id5IdSubmodule = {
id5id: {
uid: universalUid,
ext: ext
- }
+ },
};
+ if (isPlainObject(ext.euid)) {
+ responseObj.euid = {
+ uid: ext.euid.uids[0].id,
+ source: ext.euid.source,
+ ext: {provider: ID5_DOMAIN}
+ }
+ }
+
const abTestingResult = deepAccess(value, 'ab_testing.result');
switch (abTestingResult) {
case 'control':
@@ -232,7 +242,7 @@ export const id5IdSubmodule = {
getValue: function(data) {
return data.uid
},
- source: 'id5-sync.com',
+ source: ID5_DOMAIN,
atype: 1,
getUidExt: function(data) {
if (data.ext) {
@@ -240,6 +250,20 @@ export const id5IdSubmodule = {
}
}
},
+ 'euid': {
+ getValue: function (data) {
+ return data.uid;
+ },
+ getSource: function (data) {
+ return data.source;
+ },
+ atype: 3,
+ getUidExt: function (data) {
+ if (data.ext) {
+ return data.ext;
+ }
+ }
+ }
},
};
diff --git a/modules/jixieBidAdapter.js b/modules/jixieBidAdapter.js
index 75268e9d168..1e07ce6b5d8 100644
--- a/modules/jixieBidAdapter.js
+++ b/modules/jixieBidAdapter.js
@@ -295,6 +295,21 @@ export const spec = {
}
return bidResponses;
} else { return []; }
+ },
+
+ getUserSyncs: function(syncOptions, serverResponses) {
+ if (!serverResponses.length || !serverResponses[0].body || !serverResponses[0].body.userSyncs) {
+ return false;
+ }
+ let syncs = [];
+ serverResponses[0].body.userSyncs.forEach(function(sync) {
+ if (syncOptions.iframeEnabled) {
+ syncs.push(sync.uf ? { url: sync.uf, type: 'iframe' } : { url: sync.up, type: 'image' });
+ } else if (syncOptions.pixelEnabled && sync.up) {
+ syncs.push({url: sync.up, type: 'image'})
+ }
+ })
+ return syncs;
}
}
diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js
index 573ff391dae..e8c1c445816 100644
--- a/modules/jwplayerRtdProvider.js
+++ b/modules/jwplayerRtdProvider.js
@@ -192,18 +192,22 @@ export function extractPublisherParams(adUnit, fallback) {
}
function loadVat(params, onCompletion) {
- const { playerID, mediaID } = params;
+ let { playerID, playerDivId, mediaID } = params;
+ if (!playerDivId) {
+ playerDivId = playerID;
+ }
+
if (pendingRequests[mediaID] !== undefined) {
- loadVatForPendingRequest(playerID, mediaID, onCompletion);
+ loadVatForPendingRequest(playerDivId, mediaID, onCompletion);
return;
}
- const vat = getVatFromCache(mediaID) || getVatFromPlayer(playerID, mediaID) || { mediaID };
+ const vat = getVatFromCache(mediaID) || getVatFromPlayer(playerDivId, mediaID) || { mediaID };
onCompletion(vat);
}
-function loadVatForPendingRequest(playerID, mediaID, callback) {
- const vat = getVatFromPlayer(playerID, mediaID);
+function loadVatForPendingRequest(playerDivId, mediaID, callback) {
+ const vat = getVatFromPlayer(playerDivId, mediaID);
if (vat) {
callback(vat);
} else {
@@ -225,8 +229,8 @@ export function getVatFromCache(mediaID) {
};
}
-export function getVatFromPlayer(playerID, mediaID) {
- const player = getPlayer(playerID);
+export function getVatFromPlayer(playerDivId, mediaID) {
+ const player = getPlayer(playerDivId);
if (!player) {
return null;
}
@@ -362,14 +366,14 @@ export function addTargetingToBid(bid, targeting) {
bid.rtd = Object.assign({}, rtd, jwRtd);
}
-function getPlayer(playerID) {
+function getPlayer(playerDivId) {
const jwplayer = window.jwplayer;
if (!jwplayer) {
logError(SUBMODULE_NAME + '.js was not found on page');
return;
}
- const player = jwplayer(playerID);
+ const player = jwplayer(playerDivId);
if (!player || !player.getPlaylist) {
logError('player ID did not match any players');
return;
diff --git a/modules/jwplayerRtdProvider.md b/modules/jwplayerRtdProvider.md
index 479829196ed..a4c2f3621e1 100644
--- a/modules/jwplayerRtdProvider.md
+++ b/modules/jwplayerRtdProvider.md
@@ -36,7 +36,7 @@ const adUnit = {
data: {
jwTargeting: {
// Note: the following Ids are placeholders and should be replaced with your Ids.
- playerID: 'abcd',
+ playerDivId: 'abcd',
mediaID: '1234'
}
}
@@ -51,7 +51,7 @@ pbjs.que.push(function() {
});
});
```
-**Note**: The player ID is the ID of the HTML div element used when instantiating the player.
+**Note**: The player Div ID is the ID of the HTML div element used when instantiating the player.
You can retrieve this ID by calling `player.id`, where player is the JW Player instance variable.
**Note**: You may also include `jwTargeting` information in the prebid config's `ortb2.site.ext.data`. Information provided in the adUnit will always supersede, and information in the config will be used as a fallback.
diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js
index 9d8c7bc06a1..e86d7022987 100644
--- a/modules/kargoBidAdapter.js
+++ b/modules/kargoBidAdapter.js
@@ -1,4 +1,4 @@
-import { _each, isEmpty, buildUrl, deepAccess, pick, triggerPixel } from '../src/utils.js';
+import { _each, isEmpty, buildUrl, deepAccess, pick, triggerPixel, logError } from '../src/utils.js';
import { config } from '../src/config.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { getStorageManager } from '../src/storageManager.js';
@@ -95,13 +95,16 @@ function buildRequests(validBidRequests, bidderRequest) {
]
},
imp: impressions,
- user: getUserIds(tdidAdapter, bidderRequest.uspConsent, bidderRequest.gdprConsent, firstBidRequest.userIdAsEids, bidderRequest.gppConsent),
+ user: getUserIds(tdidAdapter, bidderRequest.uspConsent, bidderRequest.gdprConsent, firstBidRequest.userIdAsEids, bidderRequest.gppConsent)
});
- if (firstBidRequest.ortb2 != null) {
- krakenParams.site = {
- cat: firstBidRequest.ortb2.site.cat
+ // Add full ortb2 object as backup
+ if (firstBidRequest.ortb2) {
+ const siteCat = firstBidRequest.ortb2.site?.cat;
+ if (siteCat != null) {
+ krakenParams.site = { cat: siteCat };
}
+ krakenParams.ext = { ortb2: firstBidRequest.ortb2 };
}
// Add schain
@@ -221,7 +224,7 @@ function interpretResponse(response, bidRequest) {
width: adUnit.width,
height: adUnit.height,
ttl: 300,
- creativeId: adUnit.id,
+ creativeId: adUnit.creativeID,
dealId: adUnit.targetingCustom,
netRevenue: true,
currency: adUnit.currency || bidRequest.currency,
@@ -459,10 +462,6 @@ function getImpression(bid) {
code: bid.adUnitCode
};
- if (bid.floorData != null && bid.floorData.floorMin > 0) {
- imp.floor = bid.floorData.floorMin;
- }
-
if (bid.bidRequestsCount > 0) {
imp.bidRequestCount = bid.bidRequestsCount;
}
@@ -482,17 +481,38 @@ function getImpression(bid) {
}
}
- if (bid.mediaTypes != null) {
- if (bid.mediaTypes.banner != null) {
- imp.banner = bid.mediaTypes.banner;
+ // Add full ortb2Imp object as backup
+ if (bid.ortb2Imp) {
+ imp.ext = { ortb2Imp: bid.ortb2Imp };
+ }
+
+ if (bid.mediaTypes) {
+ const { banner, video, native } = bid.mediaTypes;
+
+ if (banner) {
+ imp.banner = banner;
+ }
+
+ if (video) {
+ imp.video = video;
}
- if (bid.mediaTypes.video != null) {
- imp.video = bid.mediaTypes.video;
+ if (native) {
+ imp.native = native;
}
- if (bid.mediaTypes.native != null) {
- imp.native = bid.mediaTypes.native;
+ if (typeof bid.getFloor === 'function') {
+ let floorInfo;
+ try {
+ floorInfo = bid.getFloor({
+ currency: 'USD',
+ mediaType: '*',
+ size: '*'
+ });
+ } catch (e) {
+ logError('Kargo: getFloor threw an error: ', e);
+ }
+ imp.floor = typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseInt(floorInfo.floor)) ? floorInfo.floor : undefined;
}
}
diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js
index 9a336b16136..264592cd7d6 100644
--- a/modules/kueezRtbBidAdapter.js
+++ b/modules/kueezRtbBidAdapter.js
@@ -173,7 +173,7 @@ function appendUserIdsToRequestPayload(payloadRef, userIds) {
function buildRequests(validBidRequests, bidderRequest) {
const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation;
- const bidderTimeout = config.getConfig('bidderTimeout');
+ const bidderTimeout = bidderRequest.timeout ?? config.getConfig('bidderTimeout');
const requests = [];
validBidRequests.forEach(validBidRequest => {
const sizes = parseSizesInput(validBidRequest.sizes);
diff --git a/modules/liveIntentIdSystem.js b/modules/liveIntentIdSystem.js
index 4e0a62cca0a..786feeb8052 100644
--- a/modules/liveIntentIdSystem.js
+++ b/modules/liveIntentIdSystem.js
@@ -11,6 +11,7 @@ import { LiveConnect } from 'live-connect-js'; // eslint-disable-line prebid/val
import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js';
import {getStorageManager} from '../src/storageManager.js';
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
+import {UID1_EIDS} from '../libraries/uid1Eids/uid1Eids.js';
import {UID2_EIDS} from '../libraries/uid2Eids/uid2Eids.js';
import { getRefererInfo } from '../src/refererDetection.js';
@@ -236,7 +237,9 @@ export const liveIntentIdSubmodule = {
}
if (value.thetradedesk) {
- result.thetradedesk = { 'id': value.thetradedesk, ext: { provider: getRefererInfo().domain || LI_PROVIDER_DOMAIN } }
+ result.lipb = {...result.lipb, tdid: value.thetradedesk}
+ result.tdid = { 'id': value.thetradedesk, ext: { rtiPartner: 'TDID', provider: getRefererInfo().domain || LI_PROVIDER_DOMAIN } }
+ delete result.lipb.thetradedesk
}
return result
@@ -278,6 +281,7 @@ export const liveIntentIdSubmodule = {
return { callback: result };
},
eids: {
+ ...UID1_EIDS,
...UID2_EIDS,
'lipb': {
getValue: function(data) {
@@ -376,18 +380,6 @@ export const liveIntentIdSubmodule = {
return data.ext;
}
}
- },
- 'thetradedesk': {
- source: 'adserver.org',
- atype: 3,
- getValue: function(data) {
- return data.id;
- },
- getUidExt: function(data) {
- if (data.ext) {
- return data.ext;
- }
- }
}
}
};
diff --git a/modules/luceadBidAdapter.js b/modules/luceadBidAdapter.js
index 8958e8f3786..ab7f96c4e60 100644
--- a/modules/luceadBidAdapter.js
+++ b/modules/luceadBidAdapter.js
@@ -1,36 +1,41 @@
import {ortbConverter} from '../libraries/ortbConverter/converter.js';
import {loadExternalScript} from '../src/adloader.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
-import {getUniqueIdentifierStr, logInfo} from '../src/utils.js';
+import {getUniqueIdentifierStr, logInfo, deepSetValue} from '../src/utils.js';
import {fetch} from '../src/ajax.js';
const bidderCode = 'lucead';
-let baseUrl = 'https://ayads.io';
-let staticUrl = 'https://s.ayads.io';
+const bidderName = 'Lucead';
+let baseUrl = 'https://lucead.com';
+let staticUrl = 'https://s.lucead.com';
let companionUrl = 'https://cdn.jsdelivr.net/gh/lucead/prebid-js-external-js-lucead@master/dist/prod.min.js';
-let endpointUrl = 'https://prebid.ayads.io/go';
+let endpointUrl = 'https://prebid.lucead.com/go';
const defaultCurrency = 'EUR';
const defaultTtl = 500;
-const isDevEnv = location.hostname.endsWith('.ngrok-free.app');
+const aliases = ['adliveplus'];
+
+function isDevEnv() {
+ return location.hash.includes('prebid-dev') || location.href.startsWith('https://ayads.io/test');
+}
function isBidRequestValid(bidRequest) {
return !!bidRequest?.params?.placementId;
}
export function log(msg, obj) {
- logInfo('Lucead - ' + msg, obj);
+ logInfo(`${bidderName} - ${msg}`, obj);
}
-function buildRequests(validBidRequests, bidderRequest) {
- if (isDevEnv) {
- baseUrl = `https://${location.hostname}`;
+function buildRequests(bidRequests, bidderRequest) {
+ if (isDevEnv()) {
+ baseUrl = location.origin;
staticUrl = baseUrl;
companionUrl = `${staticUrl}/dist/prebid-companion.js`;
endpointUrl = `${baseUrl}/go`;
}
log('buildRequests', {
- validBidRequests,
+ bidRequests,
bidderRequest,
});
@@ -39,15 +44,17 @@ function buildRequests(validBidRequests, bidderRequest) {
static_url: staticUrl,
endpoint_url: endpointUrl,
request_id: bidderRequest.bidderRequestId,
- validBidRequests,
+ prebid_version: '$prebid.version$',
+ bidRequests,
bidderRequest,
getUniqueIdentifierStr,
ortbConverter,
+ deepSetValue,
};
loadExternalScript(companionUrl, bidderCode, () => window.ayads_prebid && window.ayads_prebid(companionData));
- return validBidRequests.map(bidRequest => ({
+ return bidRequests.map(bidRequest => ({
method: 'POST',
url: `${endpointUrl}/prebid/sub`,
data: JSON.stringify({
@@ -80,7 +87,7 @@ function interpretResponse(serverResponse, bidRequest) {
height: (response?.size && response?.size?.height) || 250,
currency: response?.currency || defaultCurrency,
ttl: response?.ttl || defaultTtl,
- creativeId: response?.ad_id || '0',
+ creativeId: response.ssp ? `ssp:${response.ssp}` : (response?.ad_id || '0'),
netRevenue: response?.netRevenue || true,
ad: response?.ad || '',
meta: {
@@ -119,13 +126,22 @@ function report(type = 'impression', data = {}) {
function onBidWon(bid) {
log('Bid won', bid);
- return report(`impression`, {
+ let data = {
bid_id: bid?.bidId,
- ad_id: bid?.creativeId,
placement_id: bid?.params ? bid?.params[0]?.placementId : 0,
spent: bid?.cpm,
currency: bid?.currency,
- });
+ };
+
+ if (bid.creativeId) {
+ if (bid.creativeId.toString().startsWith('ssp:')) {
+ data.ssp = bid.creativeId.split(':')[1];
+ } else {
+ data.ad_id = bid.creativeId;
+ }
+ }
+
+ return report(`impression`, data);
}
function onTimeout(timeoutData) {
@@ -135,12 +151,13 @@ function onTimeout(timeoutData) {
export const spec = {
code: bidderCode,
// gvlid: BIDDER_GVLID,
- aliases: [],
+ aliases,
isBidRequestValid,
buildRequests,
interpretResponse,
onBidWon,
onTimeout,
+ isDevEnv,
};
// noinspection JSCheckFunctionSignatures
diff --git a/modules/luceadBidAdapter.md b/modules/luceadBidAdapter.md
index 45fd3ec5301..953c911cd2b 100644
--- a/modules/luceadBidAdapter.md
+++ b/modules/luceadBidAdapter.md
@@ -1,7 +1,9 @@
# Overview
Module Name: Lucead Bidder Adapter
+
Module Type: Bidder Adapter
+
Maintainer: prebid@lucead.com
# Description
@@ -16,9 +18,9 @@ const adUnits = [
sizes: [[300, 250]],
bids: [
{
- bidder: "lucead",
+ bidder: 'lucead',
params: {
- placementId: '1',
+ placementId: '2',
}
}
]
diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js
index 3b70a51cd68..5cc45e3adbf 100644
--- a/modules/magniteAnalyticsAdapter.js
+++ b/modules/magniteAnalyticsAdapter.js
@@ -46,6 +46,7 @@ const pbsErrorMap = {
4: 'request-error',
999: 'generic-error'
}
+let cookieless;
let prebidGlobal = getGlobal();
const {
@@ -332,10 +333,14 @@ const getTopLevelDetails = () => {
// Add DM wrapper details
if (rubiConf.wrapperName) {
+ let rule;
+ if (cookieless) {
+ rule = rubiConf.rule_name ? rubiConf.rule_name.concat('_cookieless') : 'cookieless';
+ }
payload.wrapper = {
name: rubiConf.wrapperName,
family: rubiConf.wrapperFamily,
- rule: rubiConf.rule_name
+ rule
}
}
@@ -823,6 +828,15 @@ magniteAdapter.track = ({ eventType, args }) => {
auctionData.floors = addFloorData(floorData);
}
+ // Identify chrome cookieless trafic
+ if (!cookieless) {
+ const cdep = deepAccess(args, 'bidderRequests.0.ortb2.device.ext.cdep');
+ if (cdep && (cdep.indexOf('treatment') !== -1 || cdep.indexOf('control_2') !== -1)) {
+ cookieless = 1;
+ auctionData.cdep = 1;
+ }
+ }
+
// GDPR info
const gdprData = deepAccess(args, 'bidderRequests.0.gdprConsent');
if (gdprData) {
diff --git a/modules/mediaimpactBidAdapter.js b/modules/mediaimpactBidAdapter.js
new file mode 100644
index 00000000000..9a86632f052
--- /dev/null
+++ b/modules/mediaimpactBidAdapter.js
@@ -0,0 +1,211 @@
+import {registerBidder} from '../src/adapters/bidderFactory.js';
+import { buildUrl } from '../src/utils.js'
+import {ajax} from '../src/ajax.js';
+
+const BIDDER_CODE = 'mediaimpact';
+export const ENDPOINT_PROTOCOL = 'https';
+export const ENDPOINT_DOMAIN = 'bidder.smartytouch.co';
+export const ENDPOINT_PATH = '/hb/bid';
+
+export const spec = {
+ code: BIDDER_CODE,
+
+ isBidRequestValid: function (bidRequest) {
+ return !!parseInt(bidRequest.params.unitId) || !!parseInt(bidRequest.params.partnerId);
+ },
+
+ buildRequests: function (validBidRequests, bidderRequest) {
+ // TODO does it make sense to fall back to window.location.href?
+ const referer = bidderRequest?.refererInfo?.page || window.location.href;
+
+ let bidRequests = [];
+ let beaconParams = {
+ tag: [],
+ partner: [],
+ sizes: [],
+ referer: ''
+ };
+
+ validBidRequests.forEach(function(validBidRequest) {
+ let bidRequestObject = {
+ adUnitCode: validBidRequest.adUnitCode,
+ sizes: validBidRequest.sizes,
+ bidId: validBidRequest.bidId,
+ referer: referer
+ };
+
+ if (parseInt(validBidRequest.params.unitId)) {
+ bidRequestObject.unitId = parseInt(validBidRequest.params.unitId);
+ beaconParams.tag.push(validBidRequest.params.unitId);
+ }
+
+ if (parseInt(validBidRequest.params.partnerId)) {
+ bidRequestObject.unitId = 0;
+ bidRequestObject.partnerId = parseInt(validBidRequest.params.partnerId);
+ beaconParams.partner.push(validBidRequest.params.partnerId);
+ }
+
+ bidRequests.push(bidRequestObject);
+
+ beaconParams.sizes.push(spec.joinSizesToString(validBidRequest.sizes));
+ beaconParams.referer = encodeURIComponent(referer);
+ });
+
+ if (beaconParams.partner.length > 0) {
+ beaconParams.partner = beaconParams.partner.join(',');
+ } else {
+ delete beaconParams.partner;
+ }
+
+ beaconParams.tag = beaconParams.tag.join(',');
+ beaconParams.sizes = beaconParams.sizes.join(',');
+
+ let adRequestUrl = buildUrl({
+ protocol: ENDPOINT_PROTOCOL,
+ hostname: ENDPOINT_DOMAIN,
+ pathname: ENDPOINT_PATH,
+ search: beaconParams
+ });
+
+ return {
+ method: 'POST',
+ url: adRequestUrl,
+ data: JSON.stringify(bidRequests)
+ };
+ },
+
+ joinSizesToString: function(sizes) {
+ let res = [];
+ sizes.forEach(function(size) {
+ res.push(size.join('x'));
+ });
+
+ return res.join('|');
+ },
+
+ interpretResponse: function (serverResponse, bidRequest) {
+ const validBids = JSON.parse(bidRequest.data);
+
+ if (typeof serverResponse.body === 'undefined') {
+ return [];
+ }
+
+ return validBids
+ .map(bid => ({
+ bid: bid,
+ ad: serverResponse.body[bid.adUnitCode]
+ }))
+ .filter(item => item.ad)
+ .map(item => spec.adResponse(item.bid, item.ad));
+ },
+
+ adResponse: function(bid, ad) {
+ const bidObject = {
+ requestId: bid.bidId,
+ ad: ad.ad,
+ cpm: ad.cpm,
+ width: ad.width,
+ height: ad.height,
+ ttl: 60,
+ creativeId: ad.creativeId,
+ netRevenue: ad.netRevenue,
+ currency: ad.currency,
+ winNotification: ad.winNotification
+ }
+
+ bidObject.meta = {};
+ if (ad.adomain && ad.adomain.length > 0) {
+ bidObject.meta.advertiserDomains = ad.adomain;
+ }
+
+ return bidObject;
+ },
+
+ onBidWon: function(data) {
+ data.winNotification.forEach(function(unitWon) {
+ let adBidWonUrl = buildUrl({
+ protocol: ENDPOINT_PROTOCOL,
+ hostname: ENDPOINT_DOMAIN,
+ pathname: unitWon.path
+ });
+
+ if (unitWon.method === 'POST') {
+ spec.postRequest(adBidWonUrl, JSON.stringify(unitWon.data));
+ }
+ });
+
+ return true;
+ },
+
+ postRequest(endpoint, data) {
+ ajax(endpoint, null, data, {method: 'POST'});
+ },
+
+ getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
+ const syncs = [];
+
+ if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) {
+ return syncs;
+ }
+
+ let appendGdprParams = function (url, gdprParams) {
+ if (gdprParams === null) {
+ return url;
+ }
+
+ return url + (url.indexOf('?') >= 0 ? '&' : '?') + gdprParams;
+ };
+
+ let gdprParams = null;
+ if (gdprConsent) {
+ if (typeof gdprConsent.gdprApplies === 'boolean') {
+ gdprParams = `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
+ } else {
+ gdprParams = `gdpr_consent=${gdprConsent.consentString}`;
+ }
+ }
+
+ serverResponses.forEach(resp => {
+ if (resp.body) {
+ Object.keys(resp.body).map(function(key, index) {
+ let respObject = resp.body[key];
+ if (respObject['syncs'] !== undefined &&
+ Array.isArray(respObject.syncs) &&
+ respObject.syncs.length > 0) {
+ if (syncOptions.iframeEnabled) {
+ respObject.syncs.filter(function (syncIframeObject) {
+ if (syncIframeObject['type'] !== undefined &&
+ syncIframeObject['link'] !== undefined &&
+ syncIframeObject.type === 'iframe') { return true; }
+ return false;
+ }).forEach(function (syncIframeObject) {
+ syncs.push({
+ type: 'iframe',
+ url: appendGdprParams(syncIframeObject.link, gdprParams)
+ });
+ });
+ }
+ if (syncOptions.pixelEnabled) {
+ respObject.syncs.filter(function (syncImageObject) {
+ if (syncImageObject['type'] !== undefined &&
+ syncImageObject['link'] !== undefined &&
+ syncImageObject.type === 'image') { return true; }
+ return false;
+ }).forEach(function (syncImageObject) {
+ syncs.push({
+ type: 'image',
+ url: appendGdprParams(syncImageObject.link, gdprParams)
+ });
+ });
+ }
+ }
+ });
+ }
+ });
+
+ return syncs;
+ },
+
+}
+
+registerBidder(spec);
diff --git a/modules/mediaimpactBidAdapter.md b/modules/mediaimpactBidAdapter.md
new file mode 100644
index 00000000000..2fc6697fffb
--- /dev/null
+++ b/modules/mediaimpactBidAdapter.md
@@ -0,0 +1,44 @@
+# Overview
+
+Module Name: MEDIAIMPACT Bidder Adapter
+
+Module Type: Bidder Adapter
+
+Maintainer: Info@mediaimpact.com.ua
+
+# Description
+
+You can use this adapter to get a bid from mediaimpact.com.ua.
+
+About us : https://mediaimpact.com.ua
+
+
+# Test Parameters
+```javascript
+ var adUnits = [
+ {
+ code: 'div-ad-example',
+ sizes: [[300, 250]],
+ bids: [
+ {
+ bidder: "mediaimpact",
+ params: {
+ unitId: 6698
+ }
+ }
+ ]
+ },
+ {
+ code: 'div-ad-example-2',
+ sizes: [[300, 250]],
+ bids: [
+ {
+ bidder: "mediaimpact",
+ params: {
+ partnerId: 6698
+ }
+ }
+ ]
+ }
+ ];
+```
diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js
index d151523b265..de91b508125 100644
--- a/modules/nextMillenniumBidAdapter.js
+++ b/modules/nextMillenniumBidAdapter.js
@@ -8,7 +8,6 @@ import {
getWindowTop,
isArray,
isStr,
- logMessage,
parseGPTSingleSizeArrayToRtbSize,
parseUrl,
triggerPixel,
@@ -18,7 +17,6 @@ import {getGlobal} from '../src/prebidGlobal.js';
import CONSTANTS from '../src/constants.json';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
-import * as events from '../src/events.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {getRefererInfo} from '../src/refererDetection.js';
@@ -33,18 +31,32 @@ const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric';
const TIME_TO_LIVE = 360;
const DEFAULT_CURRENCY = 'USD';
-const VIDEO_PARAMS = [
- 'api',
- 'linearity',
- 'maxduration',
- 'mimes',
- 'minduration',
- 'placement',
- 'playbackmethod',
- 'protocols',
- 'startdelay',
-];
+const VIDEO_PARAMS_DEFAULT = {
+ api: undefined,
+ context: undefined,
+ delivery: undefined,
+ linearity: undefined,
+ maxduration: undefined,
+ mimes: [
+ 'video/mp4',
+ 'video/x-ms-wmv',
+ 'application/javascript',
+ ],
+
+ minduration: undefined,
+ placement: undefined,
+ plcmt: undefined,
+ playbackend: undefined,
+ playbackmethod: undefined,
+ pos: undefined,
+ protocols: undefined,
+ skip: undefined,
+ skipafter: undefined,
+ skipmin: undefined,
+ startdelay: undefined,
+};
+const VIDEO_PARAMS = Object.keys(VIDEO_PARAMS_DEFAULT);
const ALLOWED_ORTB2_PARAMETERS = [
'site.pagecat',
'site.content.cat',
@@ -55,15 +67,6 @@ const ALLOWED_ORTB2_PARAMETERS = [
'user.keywords',
];
-const sendingDataStatistic = initSendingDataStatistic();
-events.on(CONSTANTS.EVENTS.AUCTION_INIT, auctionInitHandler);
-
-const EXPIRENCE_WURL = 20 * 60000;
-const wurlMap = {};
-cleanWurl();
-
-events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler);
-
export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],
@@ -79,7 +82,7 @@ export const spec = {
const requests = [];
window.nmmRefreshCounts = window.nmmRefreshCounts || {};
- _each(validBidRequests, function(bid) {
+ _each(validBidRequests, (bid) => {
window.nmmRefreshCounts[bid.adUnitCode] = window.nmmRefreshCounts[bid.adUnitCode] || 0;
const id = getPlacementId(bid);
const auctionId = bid.auctionId;
@@ -135,6 +138,8 @@ export const spec = {
params,
auctionId,
});
+
+ this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_REQUESTED, bid);
});
return requests;
@@ -148,11 +153,6 @@ export const spec = {
_each(resp.bid, (bid) => {
const requestId = bidRequest.bidId;
const params = bidRequest.params;
- const auctionId = bidRequest.auctionId;
- const wurl = deepAccess(bid, 'ext.prebid.events.win');
-
- // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781
- addWurl({auctionId, requestId, wurl});
const {ad, adUrl, vastUrl, vastXml} = getAd(bid);
@@ -182,6 +182,8 @@ export const spec = {
};
bidResponses.push(bidResponse);
+
+ this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_RESPONSE, bid);
});
});
@@ -215,6 +217,16 @@ export const spec = {
},
getUrlPixelMetric(eventName, bid) {
+ const disabledSending = !!config.getBidderConfig()?.nextMillennium?.disabledSendingStatisticData;
+ if (disabledSending) return;
+
+ const url = this._getUrlPixelMetric(eventName, bid);
+ if (!url) return;
+
+ triggerPixel(url);
+ },
+
+ _getUrlPixelMetric(eventName, bid) {
const bidder = bid.bidder || bid.bidderCode;
if (bidder != BIDDER_CODE) return;
@@ -248,6 +260,12 @@ export const spec = {
return url;
},
+
+ onTimeout(bids) {
+ for (const bid of bids) {
+ this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_TIMEOUT, bid);
+ };
+ },
};
export function getImp(bid, id, mediaTypes) {
@@ -263,29 +281,46 @@ export function getImp(bid, id, mediaTypes) {
},
};
- if (banner) {
- if (banner.bidfloorcur) imp.bidfloorcur = banner.bidfloorcur;
- if (banner.bidfloor) imp.bidfloor = banner.bidfloor;
+ getImpBanner(imp, banner);
+ getImpVideo(imp, video);
- imp.banner = {
- format: (banner.data?.sizes || []).map(s => { return {w: s[0], h: s[1]} }),
- };
- };
+ return imp;
+};
- if (video) {
- if (video.bidfloorcur) imp.bidfloorcur = video.bidfloorcur;
- if (video.bidfloor) imp.bidfloor = video.bidfloor;
+export function getImpBanner(imp, banner) {
+ if (!banner) return;
- imp.video = getDefinedParams(video, VIDEO_PARAMS);
- if (video.data.playerSize) {
- imp.video = Object.assign(imp.video, parseGPTSingleSizeArrayToRtbSize(video.data.playerSize) || {});
- } else if (video.w && video.h) {
- imp.video.w = video.w;
- imp.video.h = video.h;
- };
+ if (banner.bidfloorcur) imp.bidfloorcur = banner.bidfloorcur;
+ if (banner.bidfloor) imp.bidfloor = banner.bidfloor;
+
+ const format = (banner.data?.sizes || []).map(s => { return {w: s[0], h: s[1]} })
+ const {w, h} = (format[0] || {})
+ imp.banner = {
+ w,
+ h,
+ format,
};
+};
- return imp;
+export function getImpVideo(imp, video) {
+ if (!video) return;
+
+ if (video.bidfloorcur) imp.bidfloorcur = video.bidfloorcur;
+ if (video.bidfloor) imp.bidfloor = video.bidfloor;
+
+ imp.video = getDefinedParams(video.data, VIDEO_PARAMS);
+ Object.keys(VIDEO_PARAMS_DEFAULT)
+ .filter(videoParamName => VIDEO_PARAMS_DEFAULT[videoParamName])
+ .forEach(videoParamName => {
+ if (typeof imp.video[videoParamName] === 'undefined') imp.video[videoParamName] = VIDEO_PARAMS_DEFAULT[videoParamName];
+ });
+
+ if (video.data.playerSize) {
+ imp.video = Object.assign(imp.video, parseGPTSingleSizeArrayToRtbSize(video.data?.playerSize) || {});
+ } else if (video.data.w && video.data.h) {
+ imp.video.w = video.data.w;
+ imp.video.h = video.data.h;
+ };
};
export function setConsentStrings(postBody = {}, bidderRequest) {
@@ -487,126 +522,4 @@ function getSua() {
};
}
-function getKeyWurl({auctionId, requestId}) {
- return `${auctionId}-${requestId}`;
-}
-
-function addWurl({wurl, requestId, auctionId}) {
- if (!wurl) return;
-
- const expirence = Date.now() + EXPIRENCE_WURL;
- const key = getKeyWurl({auctionId, requestId});
- wurlMap[key] = {wurl, expirence};
-}
-
-function removeWurl({auctionId, requestId}) {
- const key = getKeyWurl({auctionId, requestId});
- delete wurlMap[key];
-}
-
-function getWurl({auctionId, requestId}) {
- const key = getKeyWurl({auctionId, requestId});
- return wurlMap[key] && wurlMap[key].wurl;
-}
-
-function bidWonHandler(bid) {
- const {auctionId, requestId} = bid;
- const wurl = getWurl({auctionId, requestId});
- if (wurl) {
- logMessage(`(nextmillennium) Invoking image pixel for wurl on BID_WIN: "${wurl}"`);
- triggerPixel(wurl);
- removeWurl({auctionId, requestId});
- };
-}
-
-function auctionInitHandler() {
- sendingDataStatistic.initEvents();
-}
-
-function cleanWurl() {
- const dateNow = Date.now();
- Object.keys(wurlMap).forEach(key => {
- if (dateNow >= wurlMap[key].expirence) {
- delete wurlMap[key];
- };
- });
-
- setTimeout(cleanWurl, 60000);
-}
-
-function initSendingDataStatistic() {
- class SendingDataStatistic {
- eventNames = [
- CONSTANTS.EVENTS.BID_TIMEOUT,
- CONSTANTS.EVENTS.BID_RESPONSE,
- CONSTANTS.EVENTS.BID_REQUESTED,
- CONSTANTS.EVENTS.NO_BID,
- ];
-
- disabledSending = false;
- enabledSending = false;
- eventHendlers = {};
-
- initEvents() {
- this.disabledSending = !!config.getBidderConfig()?.nextMillennium?.disabledSendingStatisticData;
- if (this.disabledSending) {
- this.removeEvents();
- } else {
- this.createEvents();
- };
- }
-
- createEvents() {
- if (this.enabledSending) return;
-
- this.enabledSending = true;
- for (let eventName of this.eventNames) {
- if (!this.eventHendlers[eventName]) {
- this.eventHendlers[eventName] = this.eventHandler(eventName);
- };
-
- events.on(eventName, this.eventHendlers[eventName]);
- };
- }
-
- removeEvents() {
- if (!this.enabledSending) return;
-
- this.enabledSending = false;
- for (let eventName of this.eventNames) {
- if (!this.eventHendlers[eventName]) continue;
-
- events.off(eventName, this.eventHendlers[eventName]);
- };
- }
-
- eventHandler(eventName) {
- const eventHandlerFunc = this.getEventHandler(eventName);
- if (eventName == CONSTANTS.EVENTS.BID_TIMEOUT) {
- return bids => {
- if (this.disabledSending || !Array.isArray(bids)) return;
-
- for (let bid of bids) {
- eventHandlerFunc(bid);
- };
- }
- };
-
- return eventHandlerFunc;
- }
-
- getEventHandler(eventName) {
- return bid => {
- if (this.disabledSending) return;
-
- const url = spec.getUrlPixelMetric(eventName, bid);
- if (!url) return;
- triggerPixel(url);
- };
- }
- };
-
- return new SendingDataStatistic();
-}
-
registerBidder(spec);
diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js
index baadaa272e6..c31c3d81aeb 100644
--- a/modules/nexx360BidAdapter.js
+++ b/modules/nexx360BidAdapter.js
@@ -22,7 +22,7 @@ const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstre
const BIDDER_CODE = 'nexx360';
const REQUEST_URL = 'https://fast.nexx360.io/booster';
const PAGE_VIEW_ID = generateUUID();
-const BIDDER_VERSION = '3.0';
+const BIDDER_VERSION = '4.0';
const GVLID = 965;
const NEXXID_KEY = 'nexx360_storage';
@@ -151,7 +151,6 @@ function isBidRequestValid(bid) {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
@@ -208,7 +207,7 @@ function interpretResponse(serverResponse) {
response.adUrl = bid.ext.adUrl;
}
}
- if ([INSTREAM, OUTSTREAM].includes(bid.ext.mediaType)) response.vastXml = bid.ext.vastXml;
+ if ([INSTREAM, OUTSTREAM].includes(bid.ext.mediaType)) response.vastXml = bid.adm;
if (bid.ext.mediaType === OUTSTREAM) {
response.renderer = createRenderer(bid, OUTSTREAM_RENDERER_URL);
diff --git a/modules/nobidAnalyticsAdapter.js b/modules/nobidAnalyticsAdapter.js
index 2c119e28610..3a272c3f796 100644
--- a/modules/nobidAnalyticsAdapter.js
+++ b/modules/nobidAnalyticsAdapter.js
@@ -6,7 +6,7 @@ import CONSTANTS from '../src/constants.json';
import adapterManager from '../src/adapterManager.js';
import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js';
-const VERSION = '2.0.0';
+const VERSION = '2.0.1';
const MODULE_NAME = 'nobidAnalyticsAdapter';
const ANALYTICS_OPT_FLUSH_TIMEOUT_SECONDS = 5 * 1000;
const RETENTION_SECONDS = 1 * 24 * 3600;
@@ -54,6 +54,7 @@ function sendEvent (event, eventType) {
return;
}
try {
+ event.version = VERSION;
const endpoint = `${resolveEndpoint()}/event/${eventType}?pubid=${nobidAnalytics.initOptions.siteId}`;
ajax(endpoint,
function (response) {
@@ -83,7 +84,7 @@ function cleanupObjectAttributes (obj, attributes) {
}
function sendBidWonEvent (event, eventType) {
const data = deepClone(event);
- cleanupObjectAttributes(data, ['bidderCode', 'size', 'statusMessage', 'adId', 'requestId', 'mediaType', 'adUnitCode', 'cpm', 'timeToRespond']);
+ cleanupObjectAttributes(data, ['bidderCode', 'size', 'statusMessage', 'adId', 'requestId', 'mediaType', 'adUnitCode', 'cpm', 'currency', 'originalCpm', 'originalCurrency', 'timeToRespond']);
if (nobidAnalytics.topLocation) data.topLocation = nobidAnalytics.topLocation;
sendEvent(data, eventType);
}
@@ -95,7 +96,7 @@ function sendAuctionEndEvent (event, eventType) {
cleanupObjectAttributes(data, ['timestamp', 'timeout', 'auctionId', 'bidderRequests', 'bidsReceived']);
if (data) cleanupObjectAttributes(data.bidderRequests, ['bidderCode', 'bidderRequestId', 'bids', 'refererInfo']);
- if (data) cleanupObjectAttributes(data.bidsReceived, ['bidderCode', 'width', 'height', 'adUnitCode', 'statusMessage', 'requestId', 'mediaType', 'cpm']);
+ if (data) cleanupObjectAttributes(data.bidsReceived, ['bidderCode', 'width', 'height', 'adUnitCode', 'statusMessage', 'requestId', 'mediaType', 'cpm', 'currency', 'originalCpm', 'originalCurrency']);
if (data) cleanupObjectAttributes(data.noBids, ['bidder', 'sizes', 'bidId']);
if (data.bidderRequests) {
data.bidderRequests.forEach(bidderRequest => {
diff --git a/modules/omsBidAdapter.js b/modules/omsBidAdapter.js
index bef9a43749f..e6c8f8b098e 100644
--- a/modules/omsBidAdapter.js
+++ b/modules/omsBidAdapter.js
@@ -45,15 +45,19 @@ function buildRequests(bidReqs, bidderRequest) {
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 = {
id: bid.bidId,
banner: {
format: processedSizes,
ext: {
- viewability: viewabilityAmountRounded
+ viewability: viewabilityAmountRounded,
}
},
+ ext: {
+ ...gpidData
+ },
tagid: String(bid.adUnitCode)
};
@@ -241,6 +245,15 @@ function _getViewability(element, topWin, {w, h} = {}) {
return getWindowTop().document.visibilityState === 'visible' ? percentInView(element, topWin, {w, h}) : 0;
}
+function _extractGpidData(bid) {
+ return {
+ gpid: bid?.ortb2Imp?.ext?.gpid,
+ adserverName: bid?.ortb2Imp?.ext?.data?.adserver?.name,
+ adslot: bid?.ortb2Imp?.ext?.data?.adserver?.adslot,
+ pbadslot: bid?.ortb2Imp?.ext?.data?.pbadslot,
+ }
+}
+
function _isIframe() {
try {
return getWindowSelf() !== getWindowTop();
diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js
index 7a7cbbadd82..d8423253aaf 100644
--- a/modules/onetagBidAdapter.js
+++ b/modules/onetagBidAdapter.js
@@ -63,7 +63,8 @@ function buildRequests(validBidRequests, bidderRequest) {
if (bidderRequest && bidderRequest.gdprConsent) {
payload.gdprConsent = {
consentString: bidderRequest.gdprConsent.consentString,
- consentRequired: bidderRequest.gdprConsent.gdprApplies
+ consentRequired: bidderRequest.gdprConsent.gdprApplies,
+ addtlConsent: bidderRequest.gdprConsent.addtlConsent
};
}
if (bidderRequest && bidderRequest.gppConsent) {
diff --git a/modules/opscoBidAdapter.js b/modules/opscoBidAdapter.js
new file mode 100644
index 00000000000..87d00f14de0
--- /dev/null
+++ b/modules/opscoBidAdapter.js
@@ -0,0 +1,129 @@
+import {deepAccess, deepSetValue, isArray, logInfo} from '../src/utils.js';
+import {registerBidder} from '../src/adapters/bidderFactory.js';
+import {BANNER} from '../src/mediaTypes.js';
+
+const ENDPOINT = 'https://exchange.ops.co/openrtb2/auction';
+const BIDDER_CODE = 'opsco';
+const DEFAULT_BID_TTL = 300;
+const DEFAULT_CURRENCY = 'USD';
+const DEFAULT_NET_REVENUE = true;
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+
+ isBidRequestValid: (bid) => !!(bid.params &&
+ bid.params.placementId &&
+ bid.params.publisherId &&
+ bid.mediaTypes?.banner?.sizes &&
+ Array.isArray(bid.mediaTypes?.banner?.sizes)),
+
+ buildRequests: (validBidRequests, bidderRequest) => {
+ const {publisherId, placementId, siteId} = validBidRequests[0].params;
+
+ const payload = {
+ id: bidderRequest.bidderRequestId,
+ imp: validBidRequests.map(bidRequest => ({
+ id: bidRequest.bidId,
+ banner: {format: extractSizes(bidRequest)},
+ ext: {
+ opsco: {
+ placementId: placementId,
+ publisherId: publisherId,
+ }
+ }
+ })),
+ site: {
+ id: siteId,
+ publisher: {id: publisherId},
+ domain: bidderRequest.refererInfo?.domain,
+ page: bidderRequest.refererInfo?.page,
+ ref: bidderRequest.refererInfo?.ref,
+ },
+ };
+
+ if (isTest(validBidRequests[0])) {
+ payload.test = 1;
+ }
+
+ if (bidderRequest.gdprConsent) {
+ deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
+ deepSetValue(payload, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0));
+ }
+ const eids = deepAccess(validBidRequests[0], 'userIdAsEids');
+ if (eids && eids.length !== 0) {
+ deepSetValue(payload, 'user.ext.eids', eids);
+ }
+
+ const schainData = deepAccess(validBidRequests[0], 'schain.nodes');
+ if (isArray(schainData) && schainData.length > 0) {
+ deepSetValue(payload, 'source.ext.schain', validBidRequests[0].schain);
+ }
+
+ if (bidderRequest.uspConsent) {
+ deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent);
+ }
+
+ return {
+ method: 'POST',
+ url: ENDPOINT,
+ data: JSON.stringify(payload),
+ };
+ },
+
+ interpretResponse: (serverResponse) => {
+ const response = (serverResponse || {}).body;
+ const bidResponses = response?.seatbid?.[0]?.bid?.map(bid => ({
+ requestId: bid.impid,
+ cpm: bid.price,
+ width: bid.w,
+ height: bid.h,
+ ad: bid.adm,
+ ttl: typeof bid.exp === 'number' ? bid.exp : DEFAULT_BID_TTL,
+ creativeId: bid.crid,
+ netRevenue: DEFAULT_NET_REVENUE,
+ currency: DEFAULT_CURRENCY,
+ meta: {advertiserDomains: bid?.adomain || []},
+ mediaType: bid.mediaType || bid.mtype
+ })) || [];
+
+ if (!bidResponses.length) {
+ logInfo('opsco.interpretResponse :: No valid responses');
+ }
+
+ return bidResponses;
+ },
+
+ getUserSyncs: (syncOptions, serverResponses) => {
+ logInfo('opsco.getUserSyncs', 'syncOptions', syncOptions, 'serverResponses', serverResponses);
+ if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) {
+ return [];
+ }
+ let syncs = [];
+ serverResponses.forEach(resp => {
+ const userSync = deepAccess(resp, 'body.ext.usersync');
+ if (userSync) {
+ const syncDetails = Object.values(userSync).flatMap(value => value.syncs || []);
+ syncDetails.forEach(syncDetail => {
+ const type = syncDetail.type === 'iframe' ? 'iframe' : 'image';
+ if ((type === 'iframe' && syncOptions.iframeEnabled) || (type === 'image' && syncOptions.pixelEnabled)) {
+ syncs.push({type, url: syncDetail.url});
+ }
+ });
+ }
+ });
+
+ logInfo('opsco.getUserSyncs result=%o', syncs);
+ return syncs;
+ }
+};
+
+function extractSizes(bidRequest) {
+ return (bidRequest.mediaTypes?.banner?.sizes || []).map(([width, height]) => ({w: width, h: height}));
+}
+
+function isTest(validBidRequest) {
+ return validBidRequest.params?.test === true;
+}
+
+registerBidder(spec);
diff --git a/modules/opscoBidAdapter.md b/modules/opscoBidAdapter.md
new file mode 100644
index 00000000000..b5e1015a325
--- /dev/null
+++ b/modules/opscoBidAdapter.md
@@ -0,0 +1,36 @@
+# Overview
+
+```
+Module Name: Opsco Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: prebid@ops.co
+```
+
+# Description
+
+Module that connects to Opscos's demand sources.
+
+# Test Parameters
+
+## Banner
+
+```
+var adUnits = [
+ {
+ code: 'test-ad',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300,600]]
+ }
+ },
+ bids: [{
+ bidder: 'opsco',
+ params: {
+ placementId: '1234',
+ publisherId: '9876',
+ test: true
+ }
+ }],
+ }
+];
+```
diff --git a/modules/pangleBidAdapter.js b/modules/pangleBidAdapter.js
index f4a52168743..c22a44687a2 100644
--- a/modules/pangleBidAdapter.js
+++ b/modules/pangleBidAdapter.js
@@ -1,4 +1,3 @@
-// ver V1.0.4
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js'
import { registerBidder } from '../src/adapters/bidderFactory.js';
@@ -155,15 +154,16 @@ export const spec = {
},
buildRequests(bidRequests, bidderRequest) {
+ const reqArr = [];
const videoBids = bidRequests.filter((bid) => isVideoBid(bid));
const bannerBids = bidRequests.filter((bid) => isBannerBid(bid));
- let requests = bannerBids.length
- ? [createRequest(bannerBids, bidderRequest, BANNER)]
- : [];
+ bannerBids.forEach((bid) => {
+ reqArr.push(createRequest([bid], bidderRequest, BANNER));
+ })
videoBids.forEach((bid) => {
- requests.push(createRequest([bid], bidderRequest, VIDEO));
+ reqArr.push(createRequest([bid], bidderRequest, VIDEO));
});
- return requests;
+ return reqArr;
},
interpretResponse(response, request) {
diff --git a/modules/pilotxBidAdapter.js b/modules/pilotxBidAdapter.js
index 0fb39e19076..417c1f0c089 100644
--- a/modules/pilotxBidAdapter.js
+++ b/modules/pilotxBidAdapter.js
@@ -45,7 +45,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
@@ -143,7 +143,7 @@ export const spec = {
/**
* Formats placement ids for adserver ingestion purposes
- * @param {string[]} The placement ID/s in an array
+ * @param {string[]} placementId the placement ID/s in an array
*/
setPlacementID: function (placementId) {
if (Array.isArray(placementId)) {
diff --git a/modules/prismaBidAdapter.js b/modules/prismaBidAdapter.js
index 4b4b5677cb3..b42c4b8af3f 100644
--- a/modules/prismaBidAdapter.js
+++ b/modules/prismaBidAdapter.js
@@ -64,7 +64,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
@@ -189,7 +189,7 @@ export const spec = {
/**
* Register bidder specific code, which will execute if a bid from this bidder won the auction
- * @param {Bid} The bid that won the auction
+ * @param {Bid} bid the bid that won the auction
*/
onBidWon: function(bid) {
// fires a pixel to confirm a winning bid
diff --git a/modules/pstudioBidAdapter.js b/modules/pstudioBidAdapter.js
new file mode 100644
index 00000000000..77a11ac58c6
--- /dev/null
+++ b/modules/pstudioBidAdapter.js
@@ -0,0 +1,435 @@
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { BANNER, VIDEO } from '../src/mediaTypes.js';
+import {
+ deepAccess,
+ isArray,
+ isNumber,
+ generateUUID,
+ isEmpty,
+ isFn,
+ isPlainObject,
+} from '../src/utils.js';
+import { getStorageManager } from '../src/storageManager.js';
+
+const BIDDER_CODE = 'pstudio';
+const ENDPOINT = 'https://exchange.pstudio.tadex.id/prebid-bid'
+const TIME_TO_LIVE = 300;
+// in case that the publisher limits number of user syncs, thisse syncs will be discarded from the end of the list
+// so more improtant syncing calls should be at the start of the list
+const USER_SYNCS = [
+ // PARTNER_UID is a partner user id
+ {
+ type: 'img',
+ url: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=k1on5ig&ttd_tpi=1&ttd_puid=%PARTNER_UID%&dsp=ttd',
+ macro: '%PARTNER_UID%',
+ },
+ {
+ type: 'img',
+ url: 'https://dsp.myads.telkomsel.com/api/v1/pixel?uid=%USERID%',
+ macro: '%USERID%',
+ },
+];
+const COOKIE_NAME = '__tadexid';
+const COOKIE_TTL_DAYS = 365;
+const DAY_IN_MS = 24 * 60 * 60 * 1000;
+const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO];
+const VIDEO_PARAMS = [
+ 'mimes',
+ 'minduration',
+ 'maxduration',
+ 'protocols',
+ 'startdelay',
+ 'placement',
+ 'skip',
+ 'skipafter',
+ 'minbitrate',
+ 'maxbitrate',
+ 'delivery',
+ 'playbackmethod',
+ 'api',
+ 'linearity',
+];
+
+export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: SUPPORTED_MEDIA_TYPES,
+
+ isBidRequestValid: function (bid) {
+ const params = bid.params || {};
+ return !!params.pubid && !!params.floorPrice && isVideoRequestValid(bid);
+ },
+
+ buildRequests: function (validBidRequests, bidderRequest) {
+ return validBidRequests.map((bid) => ({
+ method: 'POST',
+ url: ENDPOINT,
+ data: JSON.stringify(buildRequestData(bid, bidderRequest)),
+ options: {
+ contentType: 'application/json',
+ withCredentials: true,
+ },
+ }));
+ },
+
+ interpretResponse: function (serverResponse, bidRequest) {
+ const bidResponses = [];
+
+ if (!serverResponse.body.bids) return [];
+ const { id } = JSON.parse(bidRequest.data);
+
+ serverResponse.body.bids.map((bid) => {
+ const { cpm, width, height, currency, ad, meta } = bid;
+ let bidResponse = {
+ requestId: id,
+ cpm,
+ width,
+ height,
+ creativeId: bid.creative_id,
+ currency,
+ netRevenue: bid.net_revenue,
+ ttl: TIME_TO_LIVE,
+ meta: {
+ advertiserDomains: meta.advertiser_domains,
+ },
+ };
+
+ if (bid.vast_url || bid.vast_xml) {
+ bidResponse.vastUrl = bid.vast_url;
+ bidResponse.vastXml = bid.vast_xml;
+ bidResponse.mediaType = VIDEO;
+ } else {
+ bidResponse.ad = ad;
+ }
+
+ bidResponses.push(bidResponse);
+ });
+
+ return bidResponses;
+ },
+
+ getUserSyncs(_optionsType, _serverResponse, _gdprConsent, _uspConsent) {
+ const syncs = [];
+
+ let userId = readUserIdFromCookie(COOKIE_NAME);
+
+ if (!userId) {
+ userId = generateId();
+ writeIdToCookie(COOKIE_NAME, userId);
+ }
+
+ USER_SYNCS.map((userSync) => {
+ if (userSync.type === 'img') {
+ syncs.push({
+ type: 'image',
+ url: userSync.url.replace(userSync.macro, userId),
+ });
+ }
+ });
+
+ return syncs;
+ },
+};
+
+function buildRequestData(bid, bidderRequest) {
+ let payloadObject = buildBaseObject(bid, bidderRequest);
+
+ if (bid.mediaTypes.banner) {
+ return buildBannerObject(bid, payloadObject);
+ } else if (bid.mediaTypes.video) {
+ return buildVideoObject(bid, payloadObject);
+ }
+}
+
+function buildBaseObject(bid, bidderRequest) {
+ const firstPartyData = prepareFirstPartyData(bidderRequest.ortb2);
+ const { pubid, bcat, badv, bapp } = bid.params;
+ const { userId } = bid;
+ const uid2Token = userId?.uid2?.id;
+
+ if (uid2Token) {
+ if (firstPartyData.user) {
+ firstPartyData.user.uid2_token = uid2Token;
+ } else {
+ firstPartyData.user = { uid2_token: uid2Token };
+ }
+ }
+ const userCookieId = readUserIdFromCookie(COOKIE_NAME);
+ if (userCookieId) {
+ if (firstPartyData.user) {
+ firstPartyData.user.id = userCookieId;
+ } else {
+ firstPartyData.user = { id: userCookieId };
+ }
+ }
+
+ return {
+ id: bid.bidId,
+ pubid,
+ floor_price: getBidFloor(bid),
+ adtagid: bid.adUnitCode,
+ ...(bcat && { bcat }),
+ ...(badv && { badv }),
+ ...(bapp && { bapp }),
+ ...firstPartyData,
+ };
+}
+
+function buildBannerObject(bid, payloadObject) {
+ const { sizes, pos, name } = bid.mediaTypes.banner;
+
+ payloadObject.banner_properties = {
+ name,
+ sizes,
+ pos,
+ };
+
+ return payloadObject;
+}
+
+function buildVideoObject(bid, payloadObject) {
+ const { context, playerSize, w, h } = bid.mediaTypes.video;
+
+ payloadObject.video_properties = {
+ context,
+ w: w || playerSize[0][0],
+ h: h || playerSize[0][1],
+ };
+
+ for (const param of VIDEO_PARAMS) {
+ const paramValue = deepAccess(bid, `mediaTypes.video.${param}`);
+
+ if (paramValue) {
+ payloadObject.video_properties[param] = paramValue;
+ }
+ }
+
+ return payloadObject;
+}
+
+function readUserIdFromCookie(key) {
+ try {
+ const storedValue = storage.getCookie(key);
+
+ if (storedValue !== null) {
+ return storedValue;
+ }
+ } catch (error) {
+ }
+}
+
+function generateId() {
+ return generateUUID();
+}
+
+function daysToMs(days) {
+ return days * DAY_IN_MS;
+}
+
+function writeIdToCookie(key, value) {
+ if (storage.cookiesAreEnabled()) {
+ const expires = new Date(
+ Date.now() + daysToMs(parseInt(COOKIE_TTL_DAYS))
+ ).toUTCString();
+ storage.setCookie(key, value, expires, '/');
+ }
+}
+
+function prepareFirstPartyData({ user, device, site, app, regs }) {
+ let userData;
+ let deviceData;
+ let siteData;
+ let appData;
+ let regsData;
+
+ if (user) {
+ userData = {
+ yob: user.yob,
+ gender: user.gender,
+ };
+ }
+
+ if (device) {
+ deviceData = {
+ ua: device.ua,
+ dnt: device.dnt,
+ lmt: device.lmt,
+ ip: device.ip,
+ ipv6: device.ipv6,
+ devicetype: device.devicetype,
+ make: device.make,
+ model: device.model,
+ os: device.os,
+ osv: device.osv,
+ js: device.js,
+ language: device.language,
+ carrier: device.carrier,
+ connectiontype: device.connectiontype,
+ ifa: device.ifa,
+ ...(device.geo && {
+ geo: {
+ lat: device.geo.lat,
+ lon: device.geo.lon,
+ country: device.geo.country,
+ region: device.geo.region,
+ regionfips104: device.geo.regionfips104,
+ metro: device.geo.metro,
+ city: device.geo.city,
+ zip: device.geo.zip,
+ type: device.geo.type,
+ },
+ }),
+ ...(device.ext && {
+ ext: {
+ ifatype: device.ext.ifatype,
+ },
+ }),
+ };
+ }
+
+ if (site) {
+ siteData = {
+ id: site.id,
+ name: site.name,
+ domain: site.domain,
+ page: site.page,
+ cat: site.cat,
+ sectioncat: site.sectioncat,
+ pagecat: site.pagecat,
+ ref: site.ref,
+ ...(site.publisher && {
+ publisher: {
+ name: site.publisher.name,
+ cat: site.publisher.cat,
+ domain: site.publisher.domain,
+ },
+ }),
+ ...(site.content && {
+ content: {
+ id: site.content.id,
+ episode: site.content.episode,
+ title: site.content.title,
+ series: site.content.series,
+ artist: site.content.artist,
+ genre: site.content.genre,
+ album: site.content.album,
+ isrc: site.content.isrc,
+ season: site.content.season,
+ },
+ }),
+ mobile: site.mobile,
+ };
+ }
+
+ if (app) {
+ appData = {
+ id: app.id,
+ name: app.name,
+ bundle: app.bundle,
+ domain: app.domain,
+ storeurl: app.storeurl,
+ cat: app.cat,
+ sectioncat: app.sectioncat,
+ pagecat: app.pagecat,
+ ver: app.ver,
+ privacypolicy: app.privacypolicy,
+ paid: app.paid,
+ ...(app.publisher && {
+ publisher: {
+ name: app.publisher.name,
+ cat: app.publisher.cat,
+ domain: app.publisher.domain,
+ },
+ }),
+ keywords: app.keywords,
+ ...(app.content && {
+ content: {
+ id: app.content.id,
+ episode: app.content.episode,
+ title: app.content.title,
+ series: app.content.series,
+ artist: app.content.artist,
+ genre: app.content.genre,
+ album: app.content.album,
+ isrc: app.content.isrc,
+ season: app.content.season,
+ },
+ }),
+ };
+ }
+
+ if (regs) {
+ regsData = { coppa: regs.coppa };
+ }
+
+ return cleanObject({
+ user: userData,
+ device: deviceData,
+ site: siteData,
+ app: appData,
+ regs: regsData,
+ });
+}
+
+function cleanObject(data) {
+ for (let key in data) {
+ if (typeof data[key] == 'object') {
+ cleanObject(data[key]);
+
+ if (isEmpty(data[key])) delete data[key];
+ }
+
+ if (data[key] === undefined) delete data[key];
+ }
+
+ return data;
+}
+
+function isVideoRequestValid(bidRequest) {
+ if (bidRequest.mediaTypes.video) {
+ const { w, h, playerSize, mimes, protocols } = deepAccess(
+ bidRequest,
+ 'mediaTypes.video',
+ {}
+ );
+
+ const areSizesValid =
+ (isNumber(w) && isNumber(h)) || validateSizes(playerSize);
+ const areMimesValid = isArray(mimes) && mimes.length > 0;
+ const areProtocolsValid =
+ isArray(protocols) && protocols.length > 0 && protocols.every(isNumber);
+
+ return areSizesValid && areMimesValid && areProtocolsValid;
+ }
+
+ return true;
+}
+
+function validateSizes(sizes) {
+ return (
+ isArray(sizes) &&
+ sizes.length > 0 &&
+ sizes.every(
+ (size) => isArray(size) && size.length === 2 && size.every(isNumber)
+ )
+ );
+}
+
+function getBidFloor(bid) {
+ if (!isFn(bid.getFloor)) {
+ return bid.params.floorPrice ? bid.params.floorPrice : null;
+ }
+
+ let floor = bid.getFloor({
+ currency: 'USD',
+ mediaType: '*',
+ size: '*',
+ });
+ if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') {
+ return floor.floor;
+ }
+ return null;
+}
+
+registerBidder(spec);
diff --git a/modules/pstudioBidAdapter.md b/modules/pstudioBidAdapter.md
new file mode 100644
index 00000000000..0c8c6927f43
--- /dev/null
+++ b/modules/pstudioBidAdapter.md
@@ -0,0 +1,148 @@
+# Overview
+
+```
+Module Name: PStudio Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: pstudio@telkomsel.com
+```
+
+# Description
+
+Currently module supports banner as well as instream video mediaTypes.
+
+
+# Test parameters
+
+Those parameters should be used to get test responses from the adapter.
+
+```js
+var adUnits = [
+ // Banner ad unit
+ {
+ code: 'test-div-1',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]],
+ },
+ },
+ bids: [
+ {
+ bidder: 'pstudio',
+ params: {
+ // id of test publisher
+ pubid: '22430f9d-9610-432c-aabe-6134256f11af',
+ floorPrice: 1.25,
+ },
+ },
+ ],
+ },
+ // Instream video ad unit
+ {
+ code: 'test-div-2',
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ playerSize: [640, 480],
+ mimes: ['video/mp4'],
+ protocols: [3],
+ },
+ },
+ bids: [
+ {
+ bidder: 'pstudio',
+ params: {
+ // id of test publisher
+ pubid: '22430f9d-9610-432c-aabe-6134256f11af',
+ floorPrice: 1.25,
+ },
+ },
+ ],
+ },
+];
+```
+
+# Sample Banner Ad Unit
+
+```js
+var adUnits = [
+ {
+ code: 'test-div-1',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]],
+ pos: 0,
+ name: 'test-name',
+ },
+ },
+ bids: [
+ {
+ bidder: 'pstudio',
+ params: {
+ pubid: '22430f9d-9610-432c-aabe-6134256f11af', // required
+ floorPrice: 1.15, // required
+ bcat: ['IAB1-1', 'IAB1-3'], // optional
+ badv: ['nike.com'], // optional
+ bapp: ['com.foo.mygame'], // optional
+ },
+ },
+ ],
+ },
+];
+```
+
+# Sample Video Ad Unit
+
+```js
+var videoAdUnits = [
+ {
+ code: 'test-instream-video',
+ mediaTypes: {
+ video: {
+ context: 'instream', // required (only instream accepted)
+ playerSize: [640, 480], // required (alternatively it could be pair of `w` and `h` parameters)
+ mimes: ['video/mp4'], // required (only choices `video/mp4`, `application/javascript`, `video/webm` and `video/ogg` supported)
+ protocols: [2, 3], // 1 required (only choices 2 and 3 supported)
+ minduration: 5, // optional
+ maxduration: 30, // optional
+ startdelay: 5, // optional
+ placement: 1, // optional (only 1 accepted, as it is instream placement)
+ skip: 1, // optional
+ skipafter: 1, // optional
+ minbitrate: 10, // optional
+ maxbitrate: 10, // optional
+ delivery: 1, // optional
+ playbackmethod: [1, 3], // optional
+ api: [2], // optional (only choice 2 supported)
+ linearity: 1, // optional
+ },
+ },
+ bids: [
+ {
+ bidder: 'pstudio',
+ params: {
+ pubid: '22430f9d-9610-432c-aabe-6134256f11af',
+ floorPrice: 1.25,
+ badv: ['adidas.com'],
+ },
+ },
+ ],
+ },
+];
+```
+
+# Configuration for video
+
+### Prebid cache
+
+For video ads, Prebid cache must be enabled, as the demand partner does not support caching of video content.
+
+```js
+pbjs.setConfig({
+ cache: {
+ url: 'https://prebid.adnxs.com/pbc/v1/cache',
+ },
+});
+```
+
+Please provide Prebid Cache of your choice. This example uses AppNexus cache, but if you use other cache, change it according to your needs.
+
diff --git a/modules/publirBidAdapter.js b/modules/publirBidAdapter.js
new file mode 100644
index 00000000000..432e123458c
--- /dev/null
+++ b/modules/publirBidAdapter.js
@@ -0,0 +1,391 @@
+import {
+ logWarn,
+ logInfo,
+ isArray,
+ isFn,
+ deepAccess,
+ isEmpty,
+ contains,
+ timestamp,
+ triggerPixel,
+ getDNT,
+ getBidIdParameter
+} 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 { getStorageManager } from '../src/storageManager.js';
+import { ajax } from '../src/ajax.js';
+
+const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
+const BIDDER_CODE = 'publir';
+const ADAPTER_VERSION = '1.0.0';
+const TTL = 360;
+const CURRENCY = 'USD';
+const DEFAULT_SELLER_ENDPOINT = 'https://prebid.publir.com/publirPrebidEndPoint';
+const DEFAULT_IMPS_ENDPOINT = 'https://prebidimpst.publir.com/publirPrebidImpressionTracker';
+const SUPPORTED_SYNC_METHODS = {
+ IFRAME: 'iframe',
+ PIXEL: 'pixel'
+}
+
+export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
+export const spec = {
+ code: BIDDER_CODE,
+ version: ADAPTER_VERSION,
+ aliases: ['plr'],
+ supportedMediaTypes: SUPPORTED_AD_TYPES,
+ isBidRequestValid: function (bidRequest) {
+ if (!bidRequest.params.pubId) {
+ logWarn('pubId is a mandatory param for Publir adapter');
+ return false;
+ }
+
+ return true;
+ },
+ buildRequests: function (validBidRequests, bidderRequest) {
+ const reqObj = {};
+ const generalObject = validBidRequests[0];
+ reqObj.params = generatePubGeneralsParams(generalObject, bidderRequest);
+ reqObj.bids = generatePubBidParams(validBidRequests, bidderRequest);
+ reqObj.bids.timestamp = timestamp();
+ let options = {
+ withCredentials: false
+ };
+
+ return {
+ method: 'POST',
+ url: DEFAULT_SELLER_ENDPOINT,
+ data: reqObj,
+ options
+ }
+ },
+ interpretResponse: function ({ body }) {
+ const bidResponses = [];
+ if (body.bids) {
+ body.bids.forEach(adUnit => {
+ const bidResponse = {
+ requestId: adUnit.requestId,
+ cpm: adUnit.cpm,
+ currency: adUnit.currency || CURRENCY,
+ width: adUnit.width,
+ height: adUnit.height,
+ ttl: adUnit.ttl || TTL,
+ creativeId: adUnit.creativeId,
+ netRevenue: adUnit.netRevenue || true,
+ nurl: adUnit.nurl,
+ mediaType: adUnit.mediaType,
+ meta: {
+ mediaType: adUnit.mediaType
+ },
+ };
+
+ if (adUnit.mediaType === VIDEO) {
+ bidResponse.vastXml = adUnit.vastXml;
+ } else if (adUnit.mediaType === BANNER) {
+ bidResponse.ad = adUnit.ad;
+ }
+
+ if (adUnit.adomain && adUnit.adomain.length) {
+ bidResponse.meta.advertiserDomains = adUnit.adomain;
+ } else {
+ bidResponse.meta.advertiserDomains = [];
+ }
+ if (adUnit?.meta?.ad_key) {
+ bidResponse.meta.ad_key = adUnit.meta.ad_key ?? null;
+ }
+ if (adUnit.campId) {
+ bidResponse.campId = adUnit.campId;
+ }
+ bidResponse.bidder = BIDDER_CODE;
+ bidResponses.push(bidResponse);
+ });
+ } else {
+ return [];
+ }
+ return bidResponses;
+ },
+ getUserSyncs: function (syncOptions, serverResponses) {
+ const syncs = [];
+ for (const response of serverResponses) {
+ if (response.body && response.body.params) {
+ if (syncOptions.iframeEnabled && response.body.params.userSyncURL) {
+ syncs.push({
+ type: 'iframe',
+ url: response.body.params.userSyncURL
+ });
+ }
+ if (syncOptions.pixelEnabled && isArray(response.body.params.userSyncPixels)) {
+ const pixels = response.body.params.userSyncPixels.map(pixel => {
+ return {
+ type: 'image',
+ url: pixel
+ }
+ })
+ syncs.push(...pixels)
+ }
+ }
+ }
+ return syncs;
+ },
+ onBidWon: function (bid) {
+ if (bid == null) {
+ return;
+ }
+ logInfo('onBidWon:', bid);
+ ajax(DEFAULT_IMPS_ENDPOINT, null, JSON.stringify(bid), { method: 'POST', mode: 'no-cors', credentials: 'include', headers: { 'Content-Type': 'application/json' } });
+ if (bid.hasOwnProperty('nurl') && bid.nurl.length > 0) {
+ triggerPixel(bid.nurl);
+ }
+ },
+};
+
+registerBidder(spec);
+
+/**
+ * Get floor price
+ * @param bid {bid}
+ * @returns {Number}
+ */
+function getFloor(bid, mediaType) {
+ if (!isFn(bid.getFloor)) {
+ return 0;
+ }
+ let floorResult = bid.getFloor({
+ currency: CURRENCY,
+ mediaType: mediaType,
+ size: '*'
+ });
+ return floorResult.currency === CURRENCY && floorResult.floor ? floorResult.floor : 0;
+}
+
+/**
+ * Get the the ad sizes array from the bid
+ * @param bid {bid}
+ * @returns {Array}
+ */
+function getSizesArray(bid, mediaType) {
+ let sizesArray = []
+
+ if (deepAccess(bid, `mediaTypes.${mediaType}.sizes`)) {
+ sizesArray = bid.mediaTypes[mediaType].sizes;
+ } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) {
+ sizesArray = bid.sizes;
+ }
+
+ return sizesArray;
+}
+
+/**
+ * Get schain string value
+ * @param schainObject {Object}
+ * @returns {string}
+ */
+function getSupplyChain(schainObject) {
+ if (isEmpty(schainObject)) {
+ return '';
+ }
+ let scStr = `${schainObject.ver},${schainObject.complete}`;
+ schainObject.nodes.forEach((node) => {
+ scStr += '!';
+ scStr += `${getEncodedValIfNotEmpty(node.asi)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.sid)},`;
+ scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`;
+ scStr += `${getEncodedValIfNotEmpty(node.rid)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.name)},`;
+ scStr += `${getEncodedValIfNotEmpty(node.domain)}`;
+ });
+ return scStr;
+}
+
+/**
+ * Get encoded node value
+ * @param val {string}
+ * @returns {string}
+ */
+function getEncodedValIfNotEmpty(val) {
+ return !isEmpty(val) ? encodeURIComponent(val) : '';
+}
+
+function getAllowedSyncMethod(filterSettings, bidderCode) {
+ const iframeConfigsToCheck = ['all', 'iframe'];
+ const pixelConfigToCheck = 'image';
+ if (filterSettings && iframeConfigsToCheck.some(config => isSyncMethodAllowed(filterSettings[config], bidderCode))) {
+ return SUPPORTED_SYNC_METHODS.IFRAME;
+ }
+ if (!filterSettings || !filterSettings[pixelConfigToCheck] || isSyncMethodAllowed(filterSettings[pixelConfigToCheck], bidderCode)) {
+ return SUPPORTED_SYNC_METHODS.PIXEL;
+ }
+}
+
+/**
+ * Check if sync rule is supported
+ * @param syncRule {Object}
+ * @param bidderCode {string}
+ * @returns {boolean}
+ */
+function isSyncMethodAllowed(syncRule, bidderCode) {
+ if (!syncRule) {
+ return false;
+ }
+ const isInclude = syncRule.filter === 'include';
+ const bidders = isArray(syncRule.bidders) ? syncRule.bidders : [bidderCode];
+ return isInclude && contains(bidders, bidderCode);
+}
+
+/**
+ * get device type
+ * @param ua {ua}
+ * @returns {string}
+ */
+function getDeviceType(ua) {
+ if (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(ua.toLowerCase())) {
+ return '5';
+ }
+ if (/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(ua.toLowerCase())) {
+ return '4';
+ }
+ if (/smart[-_\s]?tv|hbbtv|appletv|googletv|hdmi|netcast|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b/i.test(ua.toLowerCase())) {
+ return '3';
+ }
+ return '1';
+}
+
+function generatePubBidParams(validBidRequests, bidderRequest) {
+ const bidsArray = [];
+
+ if (validBidRequests.length) {
+ validBidRequests.forEach(bid => {
+ bidsArray.push(generateBidParameters(bid, bidderRequest));
+ });
+ }
+ return bidsArray;
+}
+
+/**
+ * Generate bid specific parameters
+ * @param {bid} bid
+ * @param {bidderRequest} bidderRequest
+ * @returns {Object} bid specific params object
+ */
+function generateBidParameters(bid, bidderRequest) {
+ const { params } = bid;
+ const mediaType = isBanner(bid) ? BANNER : VIDEO;
+ const sizesArray = getSizesArray(bid, mediaType);
+
+ // fix floor price in case of NAN
+ if (isNaN(params.floorPrice)) {
+ params.floorPrice = 0;
+ }
+
+ const bidObject = {
+ mediaType,
+ adUnitCode: getBidIdParameter('adUnitCode', bid),
+ sizes: sizesArray,
+ floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice),
+ bidId: getBidIdParameter('bidId', bid),
+ bidderRequestId: getBidIdParameter('bidderRequestId', bid),
+ loop: getBidIdParameter('bidderRequestsCount', bid),
+ transactionId: bid.ortb2Imp?.ext?.tid,
+ coppa: 0
+ };
+
+ const pubId = params.pubId;
+ if (pubId) {
+ bidObject.pubId = pubId;
+ }
+
+ const sua = deepAccess(bid, `ortb2.device.sua`);
+ if (sua) {
+ bidObject.sua = sua;
+ }
+
+ const coppa = deepAccess(bid, `ortb2.regs.coppa`)
+ if (coppa) {
+ bidObject.coppa = 1;
+ }
+
+ return bidObject;
+}
+
+function isBanner(bid) {
+ return bid.mediaTypes && bid.mediaTypes.banner;
+}
+
+function getLocalStorage(cookieObjName) {
+ if (storage.localStorageIsEnabled()) {
+ const lstData = storage.getDataFromLocalStorage(cookieObjName);
+ return lstData;
+ }
+ return '';
+}
+
+/**
+ * Generate params that are common between all bids
+ * @param generalObject
+ * @param {bidderRequest} bidderRequest
+ * @returns {object} the common params object
+ */
+function generatePubGeneralsParams(generalObject, bidderRequest) {
+ const domain = bidderRequest.refererInfo;
+ const { syncEnabled, filterSettings } = config.getConfig('userSync') || {};
+ const { bidderCode } = bidderRequest;
+ const generalBidParams = generalObject.params;
+ const timeout = bidderRequest.timeout;
+ const generalParams = {
+ wrapper_type: 'prebidjs',
+ wrapper_vendor: '$$PREBID_GLOBAL$$',
+ wrapper_version: '$prebid.version$',
+ adapter_version: ADAPTER_VERSION,
+ auction_start: bidderRequest.auctionStart,
+ publisher_id: generalBidParams.pubId,
+ publisher_name: domain,
+ site_domain: domain,
+ dnt: getDNT() ? 1 : 0,
+ device_type: getDeviceType(navigator.userAgent),
+ ua: navigator.userAgent,
+ is_wrapper: !!generalBidParams.isWrapper,
+ session_id: generalBidParams.sessionId || getBidIdParameter('bidderRequestId', generalObject),
+ tmax: timeout,
+ user_cookie: getLocalStorage('_publir_prebid_creative')
+ };
+
+ const userIdsParam = getBidIdParameter('userId', generalObject);
+ if (userIdsParam) {
+ generalParams.userIds = JSON.stringify(userIdsParam);
+ }
+
+ const ortb2Metadata = bidderRequest.ortb2 || {};
+ if (ortb2Metadata.site) {
+ generalParams.site_metadata = JSON.stringify(ortb2Metadata.site);
+ }
+ if (ortb2Metadata.user) {
+ generalParams.user_metadata = JSON.stringify(ortb2Metadata.user);
+ }
+
+ if (syncEnabled) {
+ const allowedSyncMethod = getAllowedSyncMethod(filterSettings, bidderCode);
+ if (allowedSyncMethod) {
+ generalParams.cs_method = allowedSyncMethod;
+ }
+ }
+
+ if (bidderRequest.uspConsent) {
+ generalParams.us_privacy = bidderRequest.uspConsent;
+ }
+
+ if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
+ generalParams.gdpr = bidderRequest.gdprConsent.gdprApplies;
+ generalParams.gdpr_consent = bidderRequest.gdprConsent.consentString;
+ }
+
+ if (generalObject.schain) {
+ generalParams.schain = getSupplyChain(generalObject.schain);
+ }
+
+ if (bidderRequest && bidderRequest.refererInfo) {
+ generalParams.page_url = deepAccess(bidderRequest, 'refererInfo.page') || deepAccess(window, 'location.href');
+ }
+
+ return generalParams;
+}
diff --git a/modules/publirBidAdapter.md b/modules/publirBidAdapter.md
new file mode 100644
index 00000000000..872fd40c2ae
--- /dev/null
+++ b/modules/publirBidAdapter.md
@@ -0,0 +1,47 @@
+# Overview
+
+```
+Module Name: Publir Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: info@publir.com
+```
+
+
+# Description
+
+Module that connects to Publir's demand sources.
+
+The Publir adapter requires setup and approval from the Publir. Please reach out to info@publir.com to create an Publir account.
+
+The adapter supports Video(instream).
+
+# Bid Parameters
+## Video
+
+| Name | Scope | Type | Description | Example
+| ---- | ----- | ---- | ----------- | -------
+| `pubId` | required | String | Publir publisher Id provided by your Publir representative | "1234567890abcdef12345678"
+
+
+# Test Parameters
+```javascript
+var adUnits = [
+ {
+ code: 'hre_div-hre-vcn-1',
+ sizes: [[1080, 1920]]],
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [1080, 1920],
+ ],
+ },
+ },
+ bids: [{
+ bidder: 'publir',
+ params: {
+ pubId: '1234567890abcdef12345678'
+ }
+ }]
+ }
+ ];
+```
diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js
index ad2a06ea86d..ced47086f7b 100755
--- a/modules/pubmaticAnalyticsAdapter.js
+++ b/modules/pubmaticAnalyticsAdapter.js
@@ -151,6 +151,7 @@ function parseBidResponse(bid) {
'cpm', () => window.parseFloat(Number(bid.cpm).toFixed(BID_PRECISION)),
'originalCpm', () => window.parseFloat(Number(bid.originalCpm).toFixed(BID_PRECISION)),
'originalCurrency',
+ 'adserverTargeting',
'dealChannel',
'meta',
'status',
@@ -278,6 +279,7 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) {
if (isOWPubmaticBid(adapterName) && isS2SBidder(bid.bidder)) {
return;
}
+ const pg = window.parseFloat(Number(bid.bidResponse?.adserverTargeting?.hb_pb || bid.bidResponse?.adserverTargeting?.pwtpb).toFixed(BID_PRECISION));
partnerBids.push({
'pn': adapterName,
'bc': bid.bidderCode || bid.bidder,
@@ -303,7 +305,8 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) {
'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD,
'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING,
'frv': bid.bidResponse ? bid.bidResponse.floorData?.floorRuleValue : undefined,
- 'md': bid.bidResponse ? getMetadata(bid.bidResponse.meta) : undefined
+ 'md': bid.bidResponse ? getMetadata(bid.bidResponse.meta) : undefined,
+ 'pb': pg || undefined
});
});
return partnerBids;
@@ -391,7 +394,7 @@ function executeBidsLoggerCall(e, highestCpmBids) {
// getGptSlotInfoForAdUnitCode returns gptslot corresponding to adunit provided as input.
let slotObject = {
'sn': adUnitId,
- 'au': origAdUnit.adUnitId || getGptSlotInfoForAdUnitCode(adUnitId)?.gptSlot || adUnitId,
+ 'au': origAdUnit.owAdUnitId || getGptSlotInfoForAdUnitCode(adUnitId)?.gptSlot || adUnitId,
'mt': getAdUnitAdFormats(origAdUnit),
'sz': getSizesForAdUnit(adUnit, adUnitId),
'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)),
@@ -450,14 +453,16 @@ function executeBidWonLoggerCall(auctionId, adUnitId) {
return;
}
let origAdUnit = getAdUnit(cache.auctions[auctionId].origAdUnits, adUnitId) || {};
+ let owAdUnitId = origAdUnit.owAdUnitId || getGptSlotInfoForAdUnitCode(adUnitId)?.gptSlot || adUnitId;
let auctionCache = cache.auctions[auctionId];
let floorData = auctionCache.floorData;
let wiid = cache.auctions[auctionId]?.wiid || auctionId;
let referrer = config.getConfig('pageUrl') || cache.auctions[auctionId].referer || '';
let adv = winningBid.bidResponse ? getAdDomain(winningBid.bidResponse) || undefined : undefined;
let fskp = floorData ? (floorData.floorRequestData ? (floorData.floorRequestData.skipped == false ? 0 : 1) : undefined) : undefined;
-
+ let pg = window.parseFloat(Number(winningBid?.bidResponse?.adserverTargeting?.hb_pb || winningBid?.bidResponse?.adserverTargeting?.pwtpb)) || undefined;
let pixelURL = END_POINT_WIN_BID_LOGGER;
+
pixelURL += 'pubid=' + publisherId;
pixelURL += '&purl=' + enc(config.getConfig('pageUrl') || cache.auctions[auctionId].referer || '');
pixelURL += '&tst=' + Math.round((new window.Date()).getTime() / 1000);
@@ -466,7 +471,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) {
pixelURL += '&pid=' + enc(profileId);
pixelURL += '&pdvid=' + enc(profileVersionId);
pixelURL += '&slot=' + enc(adUnitId);
- pixelURL += '&au=' + enc(origAdUnit.adUnitId || adUnitId);
+ pixelURL += '&au=' + enc(owAdUnitId);
pixelURL += '&pn=' + enc(adapterName);
pixelURL += '&bc=' + enc(winningBid.bidderCode || winningBid.bidder);
pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD);
@@ -474,6 +479,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) {
pixelURL += '&kgpv=' + enc(getValueForKgpv(winningBid, adUnitId));
pixelURL += '&piid=' + enc(winningBid.bidResponse.partnerImpId || EMPTY_STRING);
pixelURL += '&di=' + enc(winningBid?.bidResponse?.dealId || OPEN_AUCTION_DEAL_ID);
+ pixelURL += '&pb=' + enc(pg);
pixelURL += '&plt=' + enc(getDevicePlatform());
pixelURL += '&psz=' + enc((winningBid?.bidResponse?.dimensions?.width || '0') + 'x' +
diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js
index d25627a7b90..f28feaa534d 100644
--- a/modules/pubmaticBidAdapter.js
+++ b/modules/pubmaticBidAdapter.js
@@ -1010,6 +1010,10 @@ export function prepareMetaObject(br, bid, seat) {
br.meta.secondaryCatIds = bid.cat;
br.meta.primaryCatId = bid.cat[0];
}
+
+ if (bid.ext && bid.ext.dsa && Object.keys(bid.ext.dsa).length) {
+ br.meta.dsa = bid.ext.dsa;
+ }
}
export const spec = {
@@ -1070,7 +1074,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: (validBidRequests, bidderRequest) => {
@@ -1217,6 +1221,11 @@ export const spec = {
deepSetValue(payload, 'regs.coppa', 1);
}
+ // dsa
+ if (bidderRequest?.ortb2?.regs?.ext?.dsa) {
+ deepSetValue(payload, 'regs.ext.dsa', bidderRequest.ortb2.regs.ext.dsa);
+ }
+
_handleEids(payload, validBidRequests);
// First Party Data
@@ -1396,6 +1405,7 @@ export const spec = {
} catch (error) {
logError(error);
}
+
return bidResponses;
},
diff --git a/modules/pubwiseBidAdapter.js b/modules/pubwiseBidAdapter.js
index 507df4a2bb0..eca0c971050 100644
--- a/modules/pubwiseBidAdapter.js
+++ b/modules/pubwiseBidAdapter.js
@@ -180,7 +180,7 @@ export const spec = {
/**
* Make a server request from the list of BidRequests.
*
- * @param {validBidRequests[]} - an array of bids
+ * @param {validBidRequests} - an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
diff --git a/modules/rasBidAdapter.js b/modules/rasBidAdapter.js
index 4e93f2aa8eb..74abd0fb4a1 100644
--- a/modules/rasBidAdapter.js
+++ b/modules/rasBidAdapter.js
@@ -1,8 +1,12 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
-import { BANNER } from '../src/mediaTypes.js';
-import { isEmpty, parseSizesInput, deepAccess } from '../src/utils.js';
-import {getAllOrtbKeywords} from '../libraries/keywords/keywords.js';
-import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js';
+import { BANNER, NATIVE } from '../src/mediaTypes.js';
+import {
+ isEmpty,
+ parseSizesInput,
+ deepAccess
+} from '../src/utils.js';
+import { getAllOrtbKeywords } from '../libraries/keywords/keywords.js';
+import { getAdUnitSizes } from '../libraries/sizeUtils/sizeUtils.js';
const BIDDER_CODE = 'ras';
const VERSION = '1.0';
@@ -56,28 +60,156 @@ function parseParams(params, bidderRequest) {
}
}
}
+ if (bidderRequest?.ortb2?.regs?.ext?.dsa?.required !== undefined) {
+ newParams.dsainfo = bidderRequest?.ortb2?.regs?.ext?.dsa?.required;
+ }
return newParams;
}
-const buildBid = (ad) => {
- if (ad.type === 'empty') {
+/**
+ * @param url string
+ * @param type number // 1 - img, 2 - js
+ * @returns an object { event: 1, method: 1 or 2, url: 'string' }
+ */
+function prepareItemEventtrackers(url, type) {
+ return {
+ event: 1,
+ method: type,
+ url: url
+ };
+}
+
+function prepareEventtrackers(emsLink, imp, impression, impression1, impressionJs1) {
+ const eventtrackers = [prepareItemEventtrackers(emsLink, 1)];
+
+ if (imp) {
+ eventtrackers.push(prepareItemEventtrackers(imp, 1));
+ }
+
+ if (impression) {
+ eventtrackers.push(prepareItemEventtrackers(impression, 1));
+ }
+
+ if (impression1) {
+ eventtrackers.push(prepareItemEventtrackers(impression1, 1));
+ }
+
+ if (impressionJs1) {
+ eventtrackers.push(prepareItemEventtrackers(impressionJs1, 2));
+ }
+
+ return eventtrackers;
+}
+
+function parseOrtbResponse(ad) {
+ if (!(ad.data?.fields && ad.data?.meta)) {
+ return false;
+ }
+
+ const { image, Image, title, url, Headline, Thirdpartyclicktracker, imp, impression, impression1, impressionJs1 } = ad.data.fields;
+ const { dsaurl, height, width, adclick } = ad.data.meta;
+ const emsLink = ad.ems_link;
+ const link = adclick + (url || Thirdpartyclicktracker);
+ const eventtrackers = prepareEventtrackers(emsLink, imp, impression, impression1, impressionJs1);
+ const ortb = {
+ ver: '1.2',
+ assets: [
+ {
+ id: 2,
+ img: {
+ url: image || Image || '',
+ w: width,
+ h: height
+ }
+ },
+ {
+ id: 4,
+ title: {
+ text: title || Headline || ''
+ }
+ },
+ {
+ id: 3,
+ data: {
+ value: deepAccess(ad, 'data.meta.advertiser_name', null),
+ type: 1
+ }
+ }
+ ],
+ link: {
+ url: link
+ },
+ eventtrackers
+ };
+
+ if (dsaurl) {
+ ortb.privacy = dsaurl
+ }
+
+ return ortb
+}
+
+function parseNativeResponse(ad) {
+ if (!(ad.data?.fields && ad.data?.meta)) {
+ return false;
+ }
+
+ const { image, Image, title, leadtext, url, Calltoaction, Body, Headline, Thirdpartyclicktracker } = ad.data.fields;
+ const { dsaurl, height, width, adclick } = ad.data.meta;
+ const link = adclick + (url || Thirdpartyclicktracker);
+ const nativeResponse = {
+ sendTargetingKeys: false,
+ title: title || Headline || '',
+ image: {
+ url: image || Image || '',
+ width,
+ height
+ },
+
+ clickUrl: link,
+ cta: Calltoaction || '',
+ body: leadtext || Body || '',
+ sponsoredBy: deepAccess(ad, 'data.meta.advertiser_name', null) || '',
+ ortb: parseOrtbResponse(ad)
+ };
+
+ if (dsaurl) {
+ nativeResponse.privacyLink = dsaurl;
+ }
+
+ return nativeResponse
+}
+
+const buildBid = (ad, mediaType) => {
+ if (ad.type === 'empty' || mediaType === undefined) {
return null;
}
- return {
+
+ const data = {
requestId: ad.id,
cpm: ad.bid_rate ? ad.bid_rate.toFixed(2) : 0,
- width: ad.width || 0,
- height: ad.height || 0,
ttl: 300,
creativeId: ad.adid ? parseInt(ad.adid.split(',')[2], 10) : 0,
netRevenue: true,
currency: ad.currency || 'USD',
dealId: null,
- meta: {
- mediaType: BANNER
- },
- ad: ad.html || null
- };
+ actgMatch: ad.actg_match || 0,
+ meta: { mediaType: BANNER },
+ mediaType: BANNER,
+ ad: ad.html || null,
+ width: ad.width || 0,
+ height: ad.height || 0
+ }
+
+ if (mediaType === 'native') {
+ data.meta = { mediaType: NATIVE };
+ data.mediaType = NATIVE;
+ data.native = parseNativeResponse(ad) || {};
+
+ delete data.ad;
+ }
+
+ return data;
};
const getContextParams = (bidRequests, bidderRequest) => {
@@ -102,18 +234,24 @@ const getSlots = (bidRequests) => {
for (let i = 0; i < batchSize; i++) {
const adunit = bidRequests[i];
const slotSequence = deepAccess(adunit, 'params.slotSequence');
-
- const sizes = parseSizesInput(getAdUnitSizes(adunit)).join(',');
+ const creFormat = getAdUnitCreFormat(adunit);
+ const sizes = creFormat === 'native' ? 'fluid' : parseSizesInput(getAdUnitSizes(adunit)).join(',');
queryString += `&slot${i}=${encodeURIComponent(adunit.params.slot)}&id${i}=${encodeURIComponent(adunit.bidId)}&composition${i}=CHILD`;
- if (sizes.length) {
+ if (creFormat === 'native') {
+ queryString += `&cre_format${i}=native`;
+ }
+
+ if (sizes) {
queryString += `&iusizes${i}=${encodeURIComponent(sizes)}`;
}
- if (slotSequence !== undefined) {
+
+ if (slotSequence !== undefined && slotSequence !== null) {
queryString += `&pos${i}=${encodeURIComponent(slotSequence)}`;
}
}
+
return queryString;
};
@@ -160,9 +298,24 @@ const parseAuctionConfigs = (serverResponse, bidRequest) => {
}
}
+const getAdUnitCreFormat = (adUnit) => {
+ if (!adUnit) {
+ return;
+ }
+
+ let creFormat = 'html';
+ let mediaTypes = Object.keys(adUnit.mediaTypes);
+
+ if (mediaTypes && mediaTypes.length === 1 && mediaTypes.includes('native')) {
+ creFormat = 'native';
+ }
+
+ return creFormat;
+}
+
export const spec = {
code: BIDDER_CODE,
- supportedMediaTypes: [BANNER],
+ supportedMediaTypes: [BANNER, NATIVE],
isBidRequestValid: function (bidRequest) {
if (!bidRequest || !bidRequest.params || typeof bidRequest.params !== 'object') {
@@ -183,7 +336,8 @@ export const spec = {
bidId: bid.bidId,
sizes: getAdUnitSizes(bid),
params: bid.params,
- fledgeEnabled: fledgeEligible
+ fledgeEnabled: fledgeEligible,
+ mediaType: (bid.mediaTypes && bid.mediaTypes.banner) ? 'display' : NATIVE
}));
return [{
@@ -195,9 +349,11 @@ export const spec = {
interpretResponse: function (serverResponse, bidRequest) {
const response = serverResponse.body;
-
const fledgeAuctionConfigs = parseAuctionConfigs(serverResponse, bidRequest);
- const bids = (!response || !response.ads || response.ads.length === 0) ? [] : response.ads.map(buildBid).filter((bid) => !isEmpty(bid));
+ const bids = (!response || !response.ads || response.ads.length === 0) ? [] : response.ads.map((ad, index) => buildBid(
+ ad,
+ bidRequest?.bidIds?.[index]?.mediaType || 'banner'
+ )).filter((bid) => !isEmpty(bid));
if (fledgeAuctionConfigs) {
// Return a tuple of bids and auctionConfigs. It is possible that bids could be null.
diff --git a/modules/rasBidAdapter.md b/modules/rasBidAdapter.md
index e8a61974130..cf169fedb63 100644
--- a/modules/rasBidAdapter.md
+++ b/modules/rasBidAdapter.md
@@ -9,7 +9,7 @@ Maintainer: support@ringpublishing.com
# Description
Module that connects to Ringer Axel Springer demand sources.
-Only banner format is supported.
+Only banner and native format is supported.
# Test Parameters
```js
@@ -49,4 +49,4 @@ var adUnits = [{
| pageContext.keyValues | optional | Object | Key-values associated with this ad unit (case-insensitive); following characters are not allowed in the values: `" ' = ! + # * ~ ; ^ ( ) < > [ ] & @` | `{}` |
| pageContext.keyValues.ci | optional | String | Content unique identifier | `"932016a5-02fc-4d5c-b643-fafc2f270f06"` |
| pageContext.keyValues.adunit | optional | String | Ad unit name | `"example_com/sport"` |
-| customParams | optional | Object | Custom request params | `{}` |
\ No newline at end of file
+| customParams | optional | Object | Custom request params | `{}` |
diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js
index cfad8fce966..1cd97696770 100644
--- a/modules/rtbhouseBidAdapter.js
+++ b/modules/rtbhouseBidAdapter.js
@@ -165,6 +165,7 @@ export const spec = {
interpretResponse: function (serverResponse, originalRequest) {
let bids;
+ const fledgeInterestGroupBuyers = config.getConfig('fledgeConfig.interestGroupBuyers') || [];
const responseBody = serverResponse.body;
let fledgeAuctionConfigs = null;
@@ -186,7 +187,7 @@ export const spec = {
{
seller,
decisionLogicUrl,
- interestGroupBuyers: Object.keys(perBuyerSignals),
+ interestGroupBuyers: [...fledgeInterestGroupBuyers, ...Object.keys(perBuyerSignals)],
perBuyerSignals,
},
sellerTimeout
diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js
index 8968d4c795a..c5308c91e18 100644
--- a/modules/rtdModule/index.js
+++ b/modules/rtdModule/index.js
@@ -1,6 +1,7 @@
/**
* This module adds Real time data support to prebid.js
* @module modules/realTimeData
+ * @typedef {import('../../modules/rtdModule/index.js').SubmoduleConfig} SubmoduleConfig
*/
/**
@@ -30,7 +31,7 @@
*/
/**
- * @function?
+ * @function
* @summary return real time data
* @name RtdSubmodule#getTargetingData
* @param {string[]} adUnitsCodes
@@ -40,7 +41,7 @@
*/
/**
- * @function?
+ * @function
* @summary modify bid request data
* @name RtdSubmodule#getBidRequestData
* @param {Object} reqBidsConfigObj
@@ -73,7 +74,7 @@
*/
/**
- * @function?
+ * @function
* @summary on auction init event
* @name RtdSubmodule#onAuctionInitEvent
* @param {Object} data
@@ -82,7 +83,7 @@
*/
/**
- * @function?
+ * @function
* @summary on auction end event
* @name RtdSubmodule#onAuctionEndEvent
* @param {Object} data
@@ -91,7 +92,7 @@
*/
/**
- * @function?
+ * @function
* @summary on bid response event
* @name RtdSubmodule#onBidResponseEvent
* @param {Object} data
@@ -100,7 +101,7 @@
*/
/**
- * @function?
+ * @function
* @summary on bid requested event
* @name RtdSubmodule#onBidRequestEvent
* @param {Object} data
@@ -109,7 +110,7 @@
*/
/**
- * @function?
+ * @function
* @summary on data deletion request
* @name RtdSubmodule#onDataDeletionRequest
* @param {SubmoduleConfig} config
diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js
index c4f6e7d545d..c03065cd5a5 100644
--- a/modules/rubiconBidAdapter.js
+++ b/modules/rubiconBidAdapter.js
@@ -201,9 +201,6 @@ export const converter = ortbConverter({
const imp = buildImp(bidRequest, context);
imp.id = bidRequest.adUnitCode;
delete imp.banner;
- if (config.getConfig('s2sConfig.defaultTtl')) {
- imp.exp = config.getConfig('s2sConfig.defaultTtl');
- };
bidRequest.params.position === 'atf' && imp.video && (imp.video.pos = 1);
bidRequest.params.position === 'btf' && imp.video && (imp.video.pos = 3);
delete imp.ext?.prebid?.storedrequest;
@@ -237,7 +234,7 @@ export const converter = ortbConverter({
},
context: {
netRevenue: rubiConf.netRevenue !== false, // If anything other than false, netRev is true
- ttl: 300,
+ ttl: 360,
},
processors: pbsExtensions
});
@@ -685,7 +682,7 @@ export const spec = {
creativeId: ad.creative_id || `${ad.network || ''}-${ad.advertiser || ''}`,
cpm: ad.cpm || 0,
dealId: ad.deal,
- ttl: 300, // 5 minutes
+ ttl: 360, // 6 minutes
netRevenue: rubiConf.netRevenue !== false, // If anything other than false, netRev is true
rubicon: {
advertiserId: ad.advertiser, networkId: ad.network
diff --git a/modules/setupadBidAdapter.js b/modules/setupadBidAdapter.js
new file mode 100644
index 00000000000..55677d51c56
--- /dev/null
+++ b/modules/setupadBidAdapter.js
@@ -0,0 +1,271 @@
+import {
+ _each,
+ createTrackPixelHtml,
+ deepAccess,
+ isStr,
+ getBidIdParameter,
+ triggerPixel,
+ logWarn,
+} from '../src/utils.js';
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { BANNER } from '../src/mediaTypes.js';
+
+const BIDDER_CODE = 'setupad';
+const ENDPOINT = 'https://prebid.setupad.io/openrtb2/auction';
+const SYNC_ENDPOINT = 'https://cookie.stpd.cloud/sync?';
+const REPORT_ENDPOINT = 'https://adapter-analytics.setupad.io/api/adapter-analytics';
+const GVLID = 1241;
+const TIME_TO_LIVE = 360;
+const biddersCreativeIds = {};
+
+function getEids(bidRequest) {
+ if (deepAccess(bidRequest, 'userIdAsEids')) return bidRequest.userIdAsEids;
+}
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+ gvlid: GVLID,
+
+ isBidRequestValid: function (bid) {
+ return !!(bid.params.placement_id && isStr(bid.params.placement_id));
+ },
+
+ buildRequests: function (validBidRequests, bidderRequest) {
+ const requests = [];
+
+ _each(validBidRequests, function (bid) {
+ const id = getBidIdParameter('placement_id', bid.params);
+ const accountId = getBidIdParameter('account_id', bid.params);
+ const auctionId = bid.auctionId;
+ const bidId = bid.bidId;
+ const eids = getEids(bid) || undefined;
+ let sizes = bid.sizes;
+ if (sizes && !Array.isArray(sizes[0])) sizes = [sizes];
+
+ const site = {
+ page: bidderRequest?.refererInfo?.page,
+ ref: bidderRequest?.refererInfo?.ref,
+ domain: bidderRequest?.refererInfo?.domain,
+ };
+ const device = {
+ w: bidderRequest?.ortb2?.device?.w,
+ h: bidderRequest?.ortb2?.device?.h,
+ };
+
+ const payload = {
+ id: bid?.bidderRequestId,
+ ext: {
+ prebid: {
+ storedrequest: {
+ id: accountId || 'default',
+ },
+ },
+ },
+ user: { ext: { eids } },
+ device,
+ site,
+ imp: [],
+ };
+
+ const imp = {
+ id: bid.adUnitCode,
+ ext: {
+ prebid: {
+ storedrequest: { id },
+ },
+ },
+ };
+
+ if (deepAccess(bid, 'mediaTypes.banner')) {
+ imp.banner = {
+ format: (sizes || []).map((s) => {
+ return { w: s[0], h: s[1] };
+ }),
+ };
+ }
+
+ payload.imp.push(imp);
+
+ const gdprConsent = bidderRequest && bidderRequest.gdprConsent;
+ const uspConsent = bidderRequest && bidderRequest.uspConsent;
+
+ if (gdprConsent || uspConsent) {
+ payload.regs = { ext: {} };
+
+ if (uspConsent) payload.regs.ext.us_privacy = uspConsent;
+
+ if (gdprConsent) {
+ if (typeof gdprConsent.gdprApplies !== 'undefined') {
+ payload.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0;
+ }
+
+ if (typeof gdprConsent.consentString !== 'undefined') {
+ payload.user.ext.consent = gdprConsent.consentString;
+ }
+ }
+ }
+ const params = bid.params;
+
+ requests.push({
+ method: 'POST',
+ url: ENDPOINT,
+ data: JSON.stringify(payload),
+ options: {
+ contentType: 'text/plain',
+ withCredentials: true,
+ },
+
+ bidId,
+ params,
+ auctionId,
+ });
+ });
+
+ return requests;
+ },
+
+ interpretResponse: function (serverResponse, bidRequest) {
+ if (
+ !serverResponse ||
+ !serverResponse.body ||
+ typeof serverResponse.body != 'object' ||
+ Object.keys(serverResponse.body).length === 0
+ ) {
+ logWarn('no response or body is malformed');
+ return [];
+ }
+
+ const serverBody = serverResponse.body;
+ const bidResponses = [];
+
+ _each(serverBody.seatbid, (res) => {
+ _each(res.bid, (bid) => {
+ const requestId = bidRequest.bidId;
+ const params = bidRequest.params;
+ const { ad, adUrl } = getAd(bid);
+
+ const bidResponse = {
+ requestId,
+ params,
+ cpm: bid.price,
+ width: bid.w,
+ height: bid.h,
+ creativeId: bid.id,
+ currency: serverBody.cur,
+ netRevenue: true,
+ ttl: TIME_TO_LIVE,
+ meta: {
+ advertiserDomains: bid.adomain || [],
+ },
+ };
+
+ // set a seat for creativeId for triggerPixel url
+ biddersCreativeIds[bidResponse.creativeId] = res.seat;
+
+ bidResponse.ad = ad;
+ bidResponse.adUrl = adUrl;
+ bidResponses.push(bidResponse);
+ });
+ });
+
+ return bidResponses;
+ },
+
+ getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
+ if (!responses?.length) return [];
+
+ const syncs = [];
+ const bidders = getBidders(responses);
+
+ if (syncOptions.iframeEnabled && bidders) {
+ const queryParams = [];
+
+ queryParams.push(`bidders=${bidders}`);
+ queryParams.push('gdpr=' + +gdprConsent.gdprApplies);
+ queryParams.push('gdpr_consent=' + gdprConsent.consentString);
+ queryParams.push('usp_consent=' + (uspConsent || ''));
+
+ const strQueryParams = queryParams.join('&');
+
+ syncs.push({
+ type: 'iframe',
+ url: SYNC_ENDPOINT + strQueryParams + '&type=iframe',
+ });
+
+ return syncs;
+ }
+
+ return [];
+ },
+
+ onBidWon: function (bid) {
+ let bidder = bid.bidder || bid.bidderCode;
+ const auctionId = bid.auctionId;
+ if (bidder !== BIDDER_CODE) return;
+
+ let params;
+ if (bid.params) {
+ params = Array.isArray(bid.params) ? bid.params : [bid.params];
+ } else {
+ if (Array.isArray(bid.bids)) {
+ params = bid.bids.map((singleBid) => singleBid.params);
+ }
+ }
+
+ if (!params?.length) return;
+
+ const placementIdsArray = [];
+ params.forEach((param) => {
+ if (!param.placement_id) return;
+ placementIdsArray.push(param.placement_id);
+ });
+
+ const placementIds = (placementIdsArray.length && placementIdsArray.join(';')) || '';
+
+ if (!placementIds) return;
+
+ let extraBidParams = '';
+
+ // find the winning bidder by using creativeId as identification
+ if (biddersCreativeIds.hasOwnProperty(bid.creativeId) && biddersCreativeIds[bid.creativeId]) {
+ bidder = biddersCreativeIds[bid.creativeId];
+ }
+
+ // Add extra parameters
+ extraBidParams = `&cpm=${bid.originalCpm}¤cy=${bid.originalCurrency}`;
+
+ const url = `${REPORT_ENDPOINT}?event=bidWon&bidder=${bidder}&placementIds=${placementIds}&auctionId=${auctionId}${extraBidParams}×tamp=${Date.now()}`;
+ triggerPixel(url);
+ },
+};
+
+function getBidders(serverResponse) {
+ const bidders = serverResponse
+ .map((res) => Object.keys(res.body.ext.responsetimemillis || []))
+ .flat(1);
+
+ if (bidders.length) {
+ return encodeURIComponent(JSON.stringify([...new Set(bidders)]));
+ }
+}
+
+function getAd(bid) {
+ let ad, adUrl;
+
+ switch (deepAccess(bid, 'ext.prebid.type')) {
+ default:
+ if (bid.adm && bid.nurl) {
+ ad = bid.adm;
+ ad += createTrackPixelHtml(decodeURIComponent(bid.nurl));
+ } else if (bid.adm) {
+ ad = bid.adm;
+ } else if (bid.nurl) {
+ adUrl = bid.nurl;
+ }
+ }
+
+ return { ad, adUrl };
+}
+
+registerBidder(spec);
diff --git a/modules/setupadBidAdapter.md b/modules/setupadBidAdapter.md
new file mode 100644
index 00000000000..0d4f0ef392e
--- /dev/null
+++ b/modules/setupadBidAdapter.md
@@ -0,0 +1,35 @@
+# Overview
+
+```text
+Module Name: Setupad Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: it@setupad.com
+```
+
+# Description
+
+Module that connects to Setupad's demand sources.
+
+# Test Parameters
+
+```js
+const adUnits = [
+ {
+ code: 'test-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]],
+ },
+ },
+ bids: [
+ {
+ bidder: 'setupad',
+ params: {
+ placement_id: '123', //required
+ account_id: '123', //optional
+ },
+ },
+ ],
+ },
+];
+```
diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js
index ae1fb131966..2264bc37ebb 100644
--- a/modules/sharethroughBidAdapter.js
+++ b/modules/sharethroughBidAdapter.js
@@ -92,6 +92,10 @@ export const sharethroughAdapterSpec = {
req.regs.ext.gpp_sid = bidderRequest.ortb2.regs.gpp_sid;
}
+ if (bidderRequest?.ortb2?.regs?.ext?.dsa) {
+ req.regs.ext.dsa = bidderRequest.ortb2.regs.ext.dsa;
+ }
+
const imps = bidRequests
.map((bidReq) => {
const impression = { ext: {} };
diff --git a/modules/smartyadsBidAdapter.js b/modules/smartyadsBidAdapter.js
index 2409bebbc59..6920983e50d 100644
--- a/modules/smartyadsBidAdapter.js
+++ b/modules/smartyadsBidAdapter.js
@@ -41,8 +41,16 @@ function getAdUrlByRegion(bid) {
try {
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const region = timezone.split('/')[0];
- if (region === 'Europe') adUrl = adUrls['EU'];
- else adUrl = adUrls['US_EAST'];
+
+ switch (region) {
+ case 'Europe':
+ adUrl = adUrls['EU'];
+ break;
+ case 'Asia':
+ adUrl = adUrls['SGP'];
+ break;
+ default: adUrl = adUrls['US_EAST'];
+ }
} catch (err) {
adUrl = adUrls['US_EAST'];
}
@@ -74,6 +82,7 @@ export const spec = {
location = winTop.location;
logMessage(e);
};
+
let placements = [];
let request = {
'deviceWidth': winTop.screen.width,
@@ -83,7 +92,9 @@ export const spec = {
'host': location.host,
'page': location.pathname,
'coppa': config.getConfig('coppa') === true ? 1 : 0,
- 'placements': placements
+ 'placements': placements,
+ 'eeid': validBidRequests[0]?.userIdAsEids,
+ 'ifa': bidderRequest?.ortb2?.device?.ifa,
};
request.language.indexOf('-') != -1 && (request.language = request.language.split('-')[0])
if (bidderRequest) {
@@ -103,8 +114,10 @@ export const spec = {
for (let i = 0; i < len; i++) {
let bid = validBidRequests[i];
+
if (i === 0) adUrl = getAdUrlByRegion(bid);
- let traff = bid.params.traffic || BANNER
+
+ let traff = bid.params.traffic || BANNER;
placements.push({
placementId: bid.params.sourceid,
bidId: bid.bidId,
diff --git a/modules/smilewantedBidAdapter.js b/modules/smilewantedBidAdapter.js
index 515aae0e092..7d4a4bca615 100644
--- a/modules/smilewantedBidAdapter.js
+++ b/modules/smilewantedBidAdapter.js
@@ -11,6 +11,10 @@ const BIDDER_CODE = 'smilewanted';
/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
+ * @typedef {import('../src/adapters/bidderFactory.js').SyncOptions} SyncOptions
+ * @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync
*/
const GVL_ID = 639;
diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js
index e786095874e..64604618680 100644
--- a/modules/sovrnBidAdapter.js
+++ b/modules/sovrnBidAdapter.js
@@ -107,18 +107,11 @@ export const spec = {
}
iv = iv || getBidIdParameter('iv', bid.params)
- const floorInfo = (bid.getFloor && typeof bid.getFloor === 'function') ? bid.getFloor({
- currency: 'USD',
- mediaType: bid.mediaTypes && bid.mediaTypes.banner ? 'banner' : 'video',
- size: '*'
- }) : {}
- floorInfo.floor = floorInfo.floor || getBidIdParameter('bidfloor', bid.params)
-
const imp = {
adunitcode: bid.adUnitCode,
id: bid.bidId,
tagid: String(getBidIdParameter('tagid', bid.params)),
- bidfloor: floorInfo.floor
+ bidfloor: _getBidFloors(bid)
}
if (deepAccess(bid, 'mediaTypes.banner')) {
@@ -332,4 +325,18 @@ function _buildVideoRequestObj(bid) {
return videoObj
}
+function _getBidFloors(bid) {
+ const floorInfo = (bid.getFloor && typeof bid.getFloor === 'function') ? bid.getFloor({
+ currency: 'USD',
+ mediaType: bid.mediaTypes && bid.mediaTypes.banner ? 'banner' : 'video',
+ size: '*'
+ }) : {}
+ const floorModuleValue = parseFloat(floorInfo.floor)
+ if (!isNaN(floorModuleValue)) {
+ return floorModuleValue
+ }
+ const paramValue = parseFloat(getBidIdParameter('bidfloor', bid.params))
+ return !isNaN(paramValue) ? paramValue : undefined
+}
+
registerBidder(spec)
diff --git a/modules/sspBCBidAdapter.js b/modules/sspBCBidAdapter.js
index c351b76d7ea..08b25abee01 100644
--- a/modules/sspBCBidAdapter.js
+++ b/modules/sspBCBidAdapter.js
@@ -12,7 +12,7 @@ const SYNC_URL = 'https://ssp.wp.pl/bidder/usersync';
const NOTIFY_URL = 'https://ssp.wp.pl/bidder/notify';
const GVLID = 676;
const TMAX = 450;
-const BIDDER_VERSION = '5.92';
+const BIDDER_VERSION = '5.93';
const DEFAULT_CURRENCY = 'PLN';
const W = window;
const { navigator } = W;
@@ -77,7 +77,7 @@ const getContentLanguage = () => {
/**
* Get Bid parameters - returns bid params from Object, or 1el array
- * @param {*} bidData - bid (bidWon), or array of bids (timeout)
+ * @param {*} bidParams - bid (bidWon), or array of bids (timeout)
* @returns {object} params object
*/
const unpackParams = (bidParams) => {
@@ -216,8 +216,11 @@ const applyTopics = (validBidRequest, ortbRequest) => {
};
const applyUserIds = (validBidRequest, ortbRequest) => {
- const eids = validBidRequest.userIdAsEids
- if (eids && eids.length) {
+ const { userIdAsEids: eidsVbr = [], ortb2 = {} } = validBidRequest;
+ const eidsOrtb = ortb2.user?.ext?.data?.eids || [];
+ const eids = [...eidsVbr, ...eidsOrtb];
+
+ if (eids.length) {
const ids = { eids };
ortbRequest.user = { ...ortbRequest.user, ...ids };
}
@@ -243,7 +246,7 @@ const applyGdpr = (bidderRequest, ortbRequest) => {
* returns floor = 0 if getFloor() is not defined
*
* @param {object} slot bid request adslot
- * @returns {float} floorprice
+ * @returns {number} floorprice
*/
const getHighestFloor = (slot) => {
const currency = getCurrency();
@@ -570,6 +573,7 @@ const parseNative = (nativeData, adUnitCode) => {
}
const renderCreative = (site, auctionId, bid, seat, request) => {
+ const { adLabel, id, slot, sn, page, publisherId, ref } = site;
let gam;
const mcad = {
@@ -619,16 +623,16 @@ const renderCreative = (site, auctionId, bid, seat, request) => {
}
Ad Content
');
+ });
+ });
+});
diff --git a/test/spec/modules/adstirBidAdapter_spec.js b/test/spec/modules/adstirBidAdapter_spec.js
index 290a6822f69..a62dce8af97 100644
--- a/test/spec/modules/adstirBidAdapter_spec.js
+++ b/test/spec/modules/adstirBidAdapter_spec.js
@@ -166,6 +166,7 @@ describe('AdstirAdapter', function () {
expect(d.ref.tloc).to.equal(bidderRequest.refererInfo.topmostLocation);
expect(d.ref.referrer).to.equal(bidderRequest.refererInfo.ref);
expect(d.sua).to.equal(null);
+ expect(d.user).to.equal(null);
expect(d.gdpr).to.equal(false);
expect(d.usp).to.equal(false);
expect(d.schain).to.equal(null);
diff --git a/test/spec/modules/asoBidAdapter_spec.js b/test/spec/modules/asoBidAdapter_spec.js
index 88016d1902c..e317a8828e7 100644
--- a/test/spec/modules/asoBidAdapter_spec.js
+++ b/test/spec/modules/asoBidAdapter_spec.js
@@ -1,30 +1,30 @@
import {expect} from 'chai';
import {spec} from 'modules/asoBidAdapter.js';
-import {parseUrl} from 'src/utils.js';
-import {BANNER, VIDEO} from 'src/mediaTypes.js';
+import {BANNER, VIDEO, NATIVE} from 'src/mediaTypes.js';
+import {OUTSTREAM} from 'src/video.js';
+import {syncAddFPDToBidderRequest} from '../../helpers/fpd';
+import {parseUrl} from '../../../src/utils';
+
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
describe('Adserver.Online bidding adapter', function () {
const bannerRequest = {
bidder: 'aso',
params: {
- zone: 1,
- attr: {
- keywords: ['a', 'b'],
- tags: ['t1', 't2']
- }
+ zone: 1
},
adUnitCode: 'adunit-banner',
+ bidId: 'bid-banner',
mediaTypes: {
- banner: {
+ [BANNER]: {
sizes: [
[300, 250],
[240, 400],
]
}
},
- bidId: 'bidid1',
- bidderRequestId: 'bidreq1',
- auctionId: 'auctionid1',
userIdAsEids: [{
source: 'src1',
uids: [
@@ -38,32 +38,67 @@ describe('Adserver.Online bidding adapter', function () {
const videoRequest = {
bidder: 'aso',
params: {
- zone: 2,
- video: {
- api: [2],
- maxduration: 30
- }
+ zone: 2
},
+ adUnitCode: 'adunit-video',
+ bidId: 'bid-video',
mediaTypes: {
- video: {
- context: 'outstream',
+ [VIDEO]: {
+ context: OUTSTREAM,
playerSize: [[640, 480]],
protocols: [1, 2],
mimes: ['video/mp4'],
}
+ }
+ };
+
+ const nativeOrtbRequest = {
+ assets: [
+ {
+ id: 0,
+ required: 1,
+ title: {
+ len: 140
+ }
+ },
+ {
+ id: 1,
+ required: 1,
+ img: {
+ type: 3,
+ w: 300,
+ h: 600
+ }
+ }]
+ };
+
+ const nativeRequest = {
+ bidder: 'aso',
+ params: {
+ zone: 3
+ },
+ adUnitCode: 'adunit-native',
+ bidId: 'bid-native',
+ mediaTypes: {
+ [NATIVE]: {
+ ortb: {
+ ...nativeOrtbRequest
+ }
+ }
},
- adUnitCode: 'adunit-video',
- bidId: 'bidid12',
- bidderRequestId: 'bidreq2',
- auctionId: 'auctionid12'
+ nativeOrtbRequest
};
const bidderRequest = {
refererInfo: {
- numIframes: 0,
+ page: 'https://example.com/page.html',
+ topmostLocation: 'https://example.com/page.html',
reachedTop: true,
- page: 'https://example.com',
- domain: 'example.com'
+ numIframes: 1,
+ stack: [
+ 'https://example.com/page.html',
+ 'https://example.com/iframe1.html'
+ ]
}
};
@@ -81,6 +116,14 @@ describe('Adserver.Online bidding adapter', function () {
}
};
+ const gdprNotApplies = {
+ gdprApplies: false,
+ consentString: '',
+ vendorData: {
+ purpose: {}
+ }
+ };
+
const uspConsent = 'usp_consent';
describe('isBidRequestValid', function () {
@@ -110,81 +153,121 @@ describe('Adserver.Online bidding adapter', function () {
});
});
- describe('buildRequests', function () {
- it('creates a valid banner request', function () {
- bannerRequest.getFloor = () => ({ currency: 'USD', floor: 0.5 });
+ describe('requests builder', function () {
+ it('should add bid floor', function () {
+ const bidRequest = Object.assign({}, bannerRequest);
+
+ bidRequest.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.5
+ }
+ };
+
+ const payload = spec.buildRequests([bidRequest], bidderRequest)[0].data;
+
+ expect(payload.imp[0].bidfloor).to.equal(0.5);
+ expect(payload.imp[0].bidfloorcur).to.equal('USD');
+ });
+ it('endpoint is valid', function () {
const requests = spec.buildRequests([bannerRequest], bidderRequest);
expect(requests).to.have.lengthOf(1);
const request = requests[0];
expect(request).to.exist;
expect(request.method).to.equal('POST');
- const parsedRequestUrl = parseUrl(request.url);
- expect(parsedRequestUrl.hostname).to.equal('srv.aso1.net');
- expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder');
+ const parsedUrl = parseUrl(request.url);
+ expect(parsedUrl.hostname).to.equal('srv.aso1.net');
+ expect(parsedUrl.pathname).to.equal('/prebid/bidder');
- const query = parsedRequestUrl.search;
+ const query = parsedUrl.search;
expect(query.pbjs).to.contain('$prebid.version$');
expect(query.zid).to.equal('1');
+ });
+ it('creates a valid banner request', function () {
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
+
+ expect(request).to.exist;
expect(request.data).to.exist;
const payload = request.data;
- expect(payload.site).to.not.equal(null);
- expect(payload.site.ref).to.equal('');
- expect(payload.site.page).to.equal('https://example.com');
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
- expect(payload.device).to.not.equal(null);
+ expect(payload.device).to.exist;
expect(payload.device.w).to.equal(window.innerWidth);
expect(payload.device.h).to.equal(window.innerHeight);
expect(payload.imp).to.have.lengthOf(1);
expect(payload.imp[0].tagid).to.equal('adunit-banner');
- expect(payload.imp[0].banner).to.not.equal(null);
- expect(payload.imp[0].banner.w).to.equal(300);
- expect(payload.imp[0].banner.h).to.equal(250);
- expect(payload.imp[0].bidfloor).to.equal(0.5);
- expect(payload.imp[0].bidfloorcur).to.equal('USD');
+ expect(payload.imp[0].banner).to.not.null;
+ expect(payload.imp[0].banner.format).to.have.lengthOf(2);
+ expect(payload.imp[0].banner.format[0].w).to.equal(300);
+ expect(payload.imp[0].banner.format[0].h).to.equal(250);
+ expect(payload.imp[0].banner.format[1].w).to.equal(240);
+ expect(payload.imp[0].banner.format[1].h).to.equal(400);
});
- it('creates a valid video request', function () {
- const requests = spec.buildRequests([videoRequest], bidderRequest);
- expect(requests).to.have.lengthOf(1);
- const request = requests[0];
+ if (FEATURES.VIDEO) {
+ it('creates a valid video request', function () {
+ const requests = spec.buildRequests([videoRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
- expect(request).to.exist;
- expect(request.method).to.equal('POST');
- const parsedRequestUrl = parseUrl(request.url);
- expect(parsedRequestUrl.hostname).to.equal('srv.aso1.net');
- expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder');
+ expect(request).to.exist;
+ expect(request.data).to.not.be.empty;
- const query = parsedRequestUrl.search;
- expect(query.pbjs).to.contain('$prebid.version$');
- expect(query.zid).to.equal('2');
+ const payload = request.data;
- expect(request.data).to.not.be.empty;
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
- const payload = request.data;
+ expect(payload.device).to.exist;
+ expect(payload.device.w).to.equal(window.innerWidth);
+ expect(payload.device.h).to.equal(window.innerHeight);
- expect(payload.site).to.not.equal(null);
- expect(payload.site.ref).to.equal('');
- expect(payload.site.page).to.equal('https://example.com');
+ expect(payload.imp).to.have.lengthOf(1);
- expect(payload.device).to.not.equal(null);
- expect(payload.device.w).to.equal(window.innerWidth);
- expect(payload.device.h).to.equal(window.innerHeight);
+ expect(payload.imp[0].tagid).to.equal('adunit-video');
+ expect(payload.imp[0].video).to.exist;
- expect(payload.imp).to.have.lengthOf(1);
+ expect(payload.imp[0].video.w).to.equal(640);
+ expect(payload.imp[0].video.h).to.equal(480);
+ expect(payload.imp[0].banner).to.not.exist;
+ });
+ }
- expect(payload.imp[0].tagid).to.equal('adunit-video');
- expect(payload.imp[0].video).to.not.equal(null);
- expect(payload.imp[0].video.w).to.equal(640);
- expect(payload.imp[0].video.h).to.equal(480);
- expect(payload.imp[0].banner).to.be.undefined;
- });
+ if (FEATURES.NATIVE) {
+ it('creates a valid native request', function () {
+ const requests = spec.buildRequests([nativeRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
+
+ expect(request).to.exist;
+ expect(request.data).to.not.be.empty;
+
+ const payload = request.data;
+
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
+
+ expect(payload.device).to.exist;
+ expect(payload.device.w).to.equal(window.innerWidth);
+ expect(payload.device.h).to.equal(window.innerHeight);
+
+ expect(payload.imp).to.have.lengthOf(1);
+
+ expect(payload.imp[0].tagid).to.equal('adunit-native');
+ expect(payload.imp[0].native).to.exist;
+ expect(payload.imp[0].native.request).to.exist;
+ });
+ }
});
describe('GDPR/USP compliance', function () {
@@ -192,7 +275,7 @@ describe('Adserver.Online bidding adapter', function () {
bidderRequest.gdprConsent = gdprConsent;
bidderRequest.uspConsent = uspConsent;
- const requests = spec.buildRequests([bannerRequest], bidderRequest);
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
expect(requests).to.have.lengthOf(1);
const request = requests[0];
@@ -209,7 +292,7 @@ describe('Adserver.Online bidding adapter', function () {
bidderRequest.gdprConsent = null;
bidderRequest.uspConsent = null;
- const requests = spec.buildRequests([bannerRequest], bidderRequest);
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
expect(requests).to.have.lengthOf(1);
const request = requests[0];
@@ -226,18 +309,21 @@ describe('Adserver.Online bidding adapter', function () {
describe('response handler', function () {
const bannerResponse = {
body: {
- id: 'auctionid1',
- bidid: 'bidid1',
seatbid: [{
bid: [
{
- impid: 'impid1',
+ impid: 'bid-banner',
price: 0.3,
crid: 321,
adm: '',
w: 300,
h: 250,
adomain: ['example.com'],
+ ext: {
+ prebid: {
+ type: 'banner'
+ }
+ }
}
]
}],
@@ -255,18 +341,48 @@ describe('Adserver.Online bidding adapter', function () {
const videoResponse = {
body: {
- id: 'auctionid2',
- bidid: 'bidid2',
seatbid: [{
bid: [
{
- impid: 'impid2',
+ impid: 'bid-video',
price: 0.5,
crid: 123,
adm: '',
adomain: ['example.com'],
w: 640,
h: 480,
+ ext: {
+ prebid: {
+ type: 'video'
+ }
+ }
+ }
+ ]
+ }],
+ cur: 'USD'
+ },
+ };
+
+ const nativeResponse = {
+ body: {
+ seatbid: [{
+ bid: [
+ {
+ impid: 'bid-native',
+ price: 0.5,
+ crid: 123,
+ adm: JSON.stringify({
+ assets: [
+ {id: 0, title: {text: 'Title'}},
+ {id: 1, img: {type: 3, url: 'https://img'}},
+ ],
+ }),
+ adomain: ['example.com'],
+ ext: {
+ prebid: {
+ type: 'native'
+ }
+ }
}
]
}],
@@ -275,47 +391,59 @@ describe('Adserver.Online bidding adapter', function () {
};
it('handles banner responses', function () {
- bannerRequest.bidRequest = {
- mediaType: BANNER
- };
- const result = spec.interpretResponse(bannerResponse, bannerRequest);
-
- expect(result).to.have.lengthOf(1);
-
- expect(result[0]).to.exist;
- expect(result[0].width).to.equal(300);
- expect(result[0].height).to.equal(250);
- expect(result[0].mediaType).to.equal(BANNER);
- expect(result[0].creativeId).to.equal(321);
- expect(result[0].cpm).to.be.within(0.1, 0.5);
- expect(result[0].ad).to.equal('');
- expect(result[0].currency).to.equal('USD');
- expect(result[0].netRevenue).to.equal(true);
- expect(result[0].ttl).to.equal(300);
- expect(result[0].dealId).to.not.exist;
- expect(result[0].meta.advertiserDomains[0]).to.equal('example.com');
+ const request = spec.buildRequests([bannerRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(bannerResponse, request);
+
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0]).to.exist;
+ expect(bids[0].width).to.equal(300);
+ expect(bids[0].height).to.equal(250);
+ expect(bids[0].mediaType).to.equal(BANNER);
+ expect(bids[0].creativeId).to.equal(321);
+ expect(bids[0].cpm).to.be.within(0.1, 0.5);
+ expect(bids[0].ad).to.equal('');
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].dealId).to.not.exist;
+ expect(bids[0].meta.advertiserDomains[0]).to.equal('example.com');
});
- it('handles video responses', function () {
- const request = {
- bidRequest: videoRequest
- };
- request.bidRequest.mediaType = VIDEO;
-
- const result = spec.interpretResponse(videoResponse, request);
- expect(result).to.have.lengthOf(1);
-
- expect(result[0].width).to.equal(640);
- expect(result[0].height).to.equal(480);
- expect(result[0].mediaType).to.equal(VIDEO);
- expect(result[0].creativeId).to.equal(123);
- expect(result[0].cpm).to.equal(0.5);
- expect(result[0].vastXml).to.equal('');
- expect(result[0].renderer).to.be.a('object');
- expect(result[0].currency).to.equal('USD');
- expect(result[0].netRevenue).to.equal(true);
- expect(result[0].ttl).to.equal(300);
- });
+ if (FEATURES.VIDEO) {
+ it('handles video responses', function () {
+ const request = spec.buildRequests([videoRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(videoResponse, request);
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0].width).to.equal(640);
+ expect(bids[0].height).to.equal(480);
+ expect(bids[0].mediaType).to.equal(VIDEO);
+ expect(bids[0].creativeId).to.equal(123);
+ expect(bids[0].cpm).to.equal(0.5);
+ expect(bids[0].vastXml).to.equal('');
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+ });
+ }
+
+ if (FEATURES.NATIVE) {
+ it('handles native responses', function () {
+ const request = spec.buildRequests([nativeRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(nativeResponse, request);
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0].mediaType).to.equal(NATIVE);
+ expect(bids[0].creativeId).to.equal(123);
+ expect(bids[0].cpm).to.equal(0.5);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+
+ expect(bids[0].native.ortb.assets).to.have.lengthOf(2);
+ });
+ }
it('handles empty responses', function () {
const response = [];
@@ -331,11 +459,27 @@ describe('Adserver.Online bidding adapter', function () {
};
it('should return iframe sync option', function () {
- expect(spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent)[0].type).to.equal('iframe');
- expect(spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent)[0].url).to.equal(
- 'sync_url?gdpr=1&consents_str=consentString&consents=1%2C2&us_privacy=usp_consent&'
+ const syncs = spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent);
+ expect(syncs).to.have.lengthOf(1);
+ expect(syncs[0].type).to.equal('iframe');
+ expect(syncs[0].url).to.equal(
+ 'sync_url?gdpr=1&consents_str=consentString&consents=1%2C2&us_privacy=usp_consent'
);
});
+
+ it('should return iframe sync option - gdpr not applies', function () {
+ const syncs = spec.getUserSyncs(syncOptions, [bannerResponse], gdprNotApplies, uspConsent);
+ expect(syncs).to.have.lengthOf(1);
+
+ expect(syncs[0].url).to.equal(
+ 'sync_url?us_privacy=usp_consent'
+ );
+ });
+
+ it('should return no sync option', function () {
+ const syncs = spec.getUserSyncs(syncOptions, [videoResponse], gdprNotApplies, uspConsent);
+ expect(syncs).to.have.lengthOf(0);
+ });
});
});
});
diff --git a/test/spec/modules/automatadAnalyticsAdapter_spec.js b/test/spec/modules/automatadAnalyticsAdapter_spec.js
index e591f7e8e95..a7dd28a8dc0 100644
--- a/test/spec/modules/automatadAnalyticsAdapter_spec.js
+++ b/test/spec/modules/automatadAnalyticsAdapter_spec.js
@@ -6,6 +6,18 @@ import spec, {self as exports} from 'modules/automatadAnalyticsAdapter.js';
import CONSTANTS from 'src/constants.json';
import { expect } from 'chai';
+const obj = {
+ auctionInitHandler: (args) => {},
+ bidResponseHandler: (args) => {},
+ bidderDoneHandler: (args) => {},
+ bidWonHandler: (args) => {},
+ noBidHandler: (args) => {},
+ auctionDebugHandler: (args) => {},
+ bidderTimeoutHandler: (args) => {},
+ bidRequestedHandler: (args) => {},
+ bidRejectedHandler: (args) => {}
+}
+
const {
AUCTION_DEBUG,
BID_REQUESTED,
@@ -117,20 +129,10 @@ describe('Automatad Analytics Adapter', () => {
describe('Behaviour of the adapter when the sdk has loaded', () => {
before(() => {
spec.enableAnalytics(CONFIG_WITH_DEBUG);
- const obj = {
- auctionInitHandler: (args) => {},
- bidResponseHandler: (args) => {},
- bidderDoneHandler: (args) => {},
- bidWonHandler: (args) => {},
- noBidHandler: (args) => {},
- auctionDebugHandler: (args) => {},
- bidderTimeoutHandler: (args) => {},
- bidRequestedHandler: (args) => {},
- bidRejectedHandler: (args) => {}
- }
global.window.atmtdAnalytics = obj
-
+ exports.qBeingUsed = false
+ exports.qTraversalComplete = undefined
Object.keys(obj).forEach((fn) => sandbox.spy(global.window.atmtdAnalytics, fn))
})
beforeEach(() => {
@@ -143,8 +145,12 @@ describe('Automatad Analytics Adapter', () => {
sandbox.restore();
});
after(() => {
+ const handlers = global.window.atmtdAnalytics
+ Object.keys(handlers).forEach((handler) => global.window.atmtdAnalytics[handler].reset())
global.window.atmtdAnalytics = undefined;
spec.disableAnalytics();
+ exports.qBeingUsed = false
+ exports.qTraversalComplete = undefined
})
it('Should call the auctionInitHandler when the auction init event is fired', () => {
@@ -298,6 +304,85 @@ describe('Automatad Analytics Adapter', () => {
});
});
+ describe('Behaviour of the adapter when the SDK has loaded midway', () => {
+ before(() => {
+ spec.enableAnalytics(CONFIG_WITH_DEBUG);
+ })
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+
+ global.window.atmtdAnalytics = undefined
+
+ exports.qBeingUsed = undefined
+ exports.qTraversalComplete = undefined
+ exports.queuePointer = 0
+ exports.retryCount = 0
+ exports.__atmtdAnalyticsQueue.length = 0
+
+ clock = sandbox.useFakeTimers();
+
+ sandbox.spy(exports.__atmtdAnalyticsQueue, 'push')
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+ after(() => {
+ spec.disableAnalytics();
+ })
+
+ it('Should push to the que when the auctionInit event is fired and push to the que even after SDK has loaded after auctionInit event', () => {
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue.push.called).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(1)
+ expect(exports.__atmtdAnalyticsQueue[0]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[0][0]).to.equal(BID_RESPONSE)
+ expect(exports.__atmtdAnalyticsQueue[0][1].type).to.equal(BID_RESPONSE)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ global.window.atmtdAnalytics = obj
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[1]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[1][0]).to.equal(BID_RESPONSE)
+ expect(exports.__atmtdAnalyticsQueue[1][1].type).to.equal(BID_RESPONSE)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ });
+
+ it('Should push to the que when the auctionInit event is fired and push to the analytics adapter handler after the que is processed', () => {
+ expect(exports.qBeingUsed).to.equal(undefined)
+ events.emit(AUCTION_INIT, {type: AUCTION_INIT})
+ global.window.atmtdAnalytics = {...obj}
+ const handlers = global.window.atmtdAnalytics
+ Object.keys(handlers).forEach((handler) => global.window.atmtdAnalytics[handler].reset())
+ expect(exports.__atmtdAnalyticsQueue.push.called).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(1)
+ expect(exports.__atmtdAnalyticsQueue[0]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[0][0]).to.equal(AUCTION_INIT)
+ expect(exports.__atmtdAnalyticsQueue[0][1].type).to.equal(AUCTION_INIT)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ expect(global.window.atmtdAnalytics.auctionInitHandler.callCount).to.equal(0)
+ clock.tick(2000)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ events.emit(NO_BID, {type: NO_BID})
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ clock.tick(1500)
+ expect(exports.qBeingUsed).to.equal(false)
+ expect(exports.qTraversalComplete).to.equal(true)
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue.push.calledThrice).to.equal(false)
+ expect(global.window.atmtdAnalytics.auctionInitHandler.calledOnce).to.equal(true)
+ expect(global.window.atmtdAnalytics.noBidHandler.calledOnce).to.equal(true)
+ expect(global.window.atmtdAnalytics.bidResponseHandler.calledOnce).to.equal(true)
+ });
+ });
+
describe('Process Events from Que when SDK still has not loaded', () => {
before(() => {
spec.enableAnalytics({
@@ -312,6 +397,8 @@ describe('Automatad Analytics Adapter', () => {
sandbox.stub(exports.__atmtdAnalyticsQueue, 'push').callsFake((args) => {
Array.prototype.push.apply(exports.__atmtdAnalyticsQueue, [args]);
})
+ exports.queuePointer = 0;
+ exports.retryCount = 0;
})
beforeEach(() => {
sandbox = sinon.createSandbox();
@@ -326,7 +413,6 @@ describe('Automatad Analytics Adapter', () => {
sandbox.restore();
exports.queuePointer = 0;
exports.retryCount = 0;
- exports.__atmtdAnalyticsQueue = []
spec.disableAnalytics();
})
@@ -437,7 +523,6 @@ describe('Automatad Analytics Adapter', () => {
}
});
sandbox = sinon.createSandbox();
- sandbox.reset()
const obj = {
auctionInitHandler: (args) => {},
bidResponseHandler: (args) => {},
@@ -473,8 +558,10 @@ describe('Automatad Analytics Adapter', () => {
['impressionViewable', {type: 'impressionViewable'}]
]
});
- after(() => {
+ afterEach(() => {
sandbox.restore();
+ })
+ after(() => {
spec.disableAnalytics();
})
diff --git a/test/spec/modules/azerionedgeRtdProvider_spec.js b/test/spec/modules/azerionedgeRtdProvider_spec.js
new file mode 100644
index 00000000000..f08aaebdf55
--- /dev/null
+++ b/test/spec/modules/azerionedgeRtdProvider_spec.js
@@ -0,0 +1,183 @@
+import { config } from 'src/config.js';
+import * as azerionedgeRTD from 'modules/azerionedgeRtdProvider.js';
+import { loadExternalScript } from '../../../src/adloader.js';
+
+describe('Azerion Edge RTD submodule', function () {
+ const STORAGE_KEY = 'ht-pa-v1-a';
+ const USER_AUDIENCES = [
+ { id: '1', visits: 123 },
+ { id: '2', visits: 456 },
+ ];
+
+ const key = 'publisher123';
+ const bidders = ['appnexus', 'improvedigital'];
+ const process = { key: 'value' };
+ const dataProvider = { name: 'azerionedge', waitForIt: true };
+
+ let reqBidsConfigObj;
+ let storageStub;
+
+ beforeEach(function () {
+ config.resetConfig();
+ reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+ window.azerionPublisherAudiences = sinon.spy();
+ storageStub = sinon.stub(azerionedgeRTD.storage, 'getDataFromLocalStorage');
+ });
+
+ afterEach(function () {
+ delete window.azerionPublisherAudiences;
+ storageStub.restore();
+ });
+
+ describe('initialisation', function () {
+ let returned;
+
+ beforeEach(function () {
+ returned = azerionedgeRTD.azerionedgeSubmodule.init(dataProvider);
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should load external script', function () {
+ expect(loadExternalScript.called).to.be.true;
+ });
+
+ it('should load external script with default versioned url', function () {
+ const expected = 'https://edge.hyth.io/js/v1/azerion-edge.min.js';
+ expect(loadExternalScript.args[0][0]).to.deep.equal(expected);
+ });
+
+ it('should call azerionPublisherAudiencesStub with empty configuration', function () {
+ expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal({});
+ });
+
+ describe('with key', function () {
+ beforeEach(function () {
+ window.azerionPublisherAudiences.resetHistory();
+ loadExternalScript.resetHistory();
+ returned = azerionedgeRTD.azerionedgeSubmodule.init({
+ ...dataProvider,
+ params: { key },
+ });
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should load external script with publisher id url', function () {
+ const expected = `https://edge.hyth.io/js/v1/${key}/azerion-edge.min.js`;
+ expect(loadExternalScript.args[0][0]).to.deep.equal(expected);
+ });
+ });
+
+ describe('with process configuration', function () {
+ beforeEach(function () {
+ window.azerionPublisherAudiences.resetHistory();
+ loadExternalScript.resetHistory();
+ returned = azerionedgeRTD.azerionedgeSubmodule.init({
+ ...dataProvider,
+ params: { process },
+ });
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should call azerionPublisherAudiencesStub with process configuration', function () {
+ expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal(
+ process
+ );
+ });
+ });
+ });
+
+ describe('gets audiences', function () {
+ let callbackStub;
+
+ beforeEach(function () {
+ callbackStub = sinon.mock();
+ });
+
+ describe('with empty storage', function () {
+ beforeEach(function () {
+ azerionedgeRTD.azerionedgeSubmodule.getBidRequestData(
+ reqBidsConfigObj,
+ callbackStub,
+ dataProvider
+ );
+ });
+
+ it('does not run apply audiences to bidders', function () {
+ expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({});
+ });
+
+ it('calls callback anyway', function () {
+ expect(callbackStub.called).to.be.true;
+ });
+ });
+
+ describe('with populate storage', function () {
+ beforeEach(function () {
+ storageStub
+ .withArgs(STORAGE_KEY)
+ .returns(JSON.stringify(USER_AUDIENCES));
+ azerionedgeRTD.azerionedgeSubmodule.getBidRequestData(
+ reqBidsConfigObj,
+ callbackStub,
+ dataProvider
+ );
+ });
+
+ it('does apply audiences to bidder', function () {
+ const segments =
+ reqBidsConfigObj.ortb2Fragments.bidder['improvedigital'].user.data[0]
+ .segment;
+ expect(segments).to.deep.equal([{ id: '1' }, { id: '2' }]);
+ });
+
+ it('calls callback always', function () {
+ expect(callbackStub.called).to.be.true;
+ });
+ });
+ });
+
+ describe('sets audiences in bidder', function () {
+ const audiences = USER_AUDIENCES.map(({ id }) => id);
+ const expected = {
+ user: {
+ data: [
+ {
+ ext: { segtax: 4 },
+ name: 'azerionedge',
+ segment: [{ id: '1' }, { id: '2' }],
+ },
+ ],
+ },
+ };
+
+ it('for improvedigital by default', function () {
+ azerionedgeRTD.setAudiencesToBidders(
+ reqBidsConfigObj,
+ dataProvider,
+ audiences
+ );
+ expect(
+ reqBidsConfigObj.ortb2Fragments.bidder['improvedigital']
+ ).to.deep.equal(expected);
+ });
+
+ bidders.forEach((bidder) => {
+ it(`for ${bidder}`, function () {
+ const config = { ...dataProvider, params: { bidders } };
+ azerionedgeRTD.setAudiencesToBidders(reqBidsConfigObj, config, audiences);
+ expect(reqBidsConfigObj.ortb2Fragments.bidder[bidder]).to.deep.equal(
+ expected
+ );
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/cointrafficBidAdapter_spec.js b/test/spec/modules/cointrafficBidAdapter_spec.js
index 79775f7b135..21f02b4f8ef 100644
--- a/test/spec/modules/cointrafficBidAdapter_spec.js
+++ b/test/spec/modules/cointrafficBidAdapter_spec.js
@@ -4,6 +4,11 @@ import { spec } from 'modules/cointrafficBidAdapter.js';
import { config } from 'src/config.js'
import * as utils from 'src/utils.js'
+/**
+ * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ */
+
const ENDPOINT_URL = 'https://apps-pbd.ctraffic.io/pb/tmp';
describe('cointrafficBidAdapter', function () {
diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js
index b8c872d879d..ebe1e9be4d4 100644
--- a/test/spec/modules/colossussspBidAdapter_spec.js
+++ b/test/spec/modules/colossussspBidAdapter_spec.js
@@ -255,13 +255,46 @@ describe('ColossussspAdapter', function () {
});
describe('buildRequests with user ids', function () {
- bid.userId = {}
- bid.userId.britepoolid = 'britepoolid123';
- bid.userId.idl_env = 'idl_env123';
- bid.userId.tdid = 'tdid123';
- bid.userId.id5id = { uid: 'id5id123' };
- bid.userId.uid2 = { id: 'uid2id123' };
- let serverRequest = spec.buildRequests([bid], bidderRequest);
+ var clonedBid = JSON.parse(JSON.stringify(bid));
+ clonedBid.userId = {}
+ clonedBid.userId.britepoolid = 'britepoolid123';
+ clonedBid.userId.idl_env = 'idl_env123';
+ clonedBid.userId.tdid = 'tdid123';
+ clonedBid.userId.id5id = { uid: 'id5id123' };
+ clonedBid.userId.uid2 = { id: 'uid2id123' };
+ clonedBid.userIdAsEids = [
+ {
+ 'source': 'pubcid.org',
+ 'uids': [
+ {
+ 'id': '4679e98e-1d83-4718-8aba-aa88hhhaaa',
+ 'atype': 1
+ }
+ ]
+ },
+ {
+ 'source': 'adserver.org',
+ 'uids': [
+ {
+ 'id': 'e804908e-57b4-4f46-a097-08be44321e79',
+ 'atype': 1,
+ 'ext': {
+ 'rtiPartner': 'TDID'
+ }
+ }
+ ]
+ },
+ {
+ 'source': 'neustar.biz',
+ 'uids': [
+ {
+ 'id': 'E1:Bvss1x8hXM2zHeqiqj2umJUziavSvLT6E_ORri5fDCsZb-5sfD18oNWycTmdx6QBNdbURBVv466hLJiKSwHCaTxvROo8smjqj6GfvlKfzQI',
+ 'atype': 1
+ }
+ ]
+ }
+ ];
+ let serverRequest = spec.buildRequests([clonedBid], bidderRequest);
it('Returns valid data if array of bids is valid', function () {
let data = serverRequest.data;
let placements = data['placements'];
@@ -270,11 +303,11 @@ describe('ColossussspAdapter', function () {
let placement = placements[i];
expect(placement).to.have.property('eids')
expect(placement.eids).to.be.an('array')
- expect(placement.eids.length).to.be.equal(5)
+ expect(placement.eids.length).to.be.equal(8)
for (let index in placement.eids) {
let v = placement.eids[index];
expect(v).to.have.all.keys('source', 'uids')
- expect(v.source).to.be.oneOf(['britepool.com', 'identityLink', 'adserver.org', 'id5-sync.com', 'uidapi.com'])
+ expect(v.source).to.be.oneOf(['pubcid.org', 'adserver.org', 'neustar.biz', 'britepool.com', 'identityLink', 'id5-sync.com', 'adserver.org', 'uidapi.com'])
expect(v.uids).to.be.an('array');
expect(v.uids.length).to.be.equal(1)
expect(v.uids[0]).to.have.property('id')
diff --git a/test/spec/modules/connatixBidAdapter_spec.js b/test/spec/modules/connatixBidAdapter_spec.js
index 78f6a9d410d..4d816c4e816 100644
--- a/test/spec/modules/connatixBidAdapter_spec.js
+++ b/test/spec/modules/connatixBidAdapter_spec.js
@@ -90,6 +90,10 @@ describe('connatixBidAdapter', function () {
gdprApplies: true
},
uspConsent: '1YYY',
+ gppConsent: {
+ gppString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==',
+ applicableSections: [7]
+ },
ortb2: {
site: {
data: {
@@ -128,6 +132,7 @@ describe('connatixBidAdapter', function () {
expect(serverRequest.data.refererInfo).to.equal(bidderRequest.refererInfo);
expect(serverRequest.data.gdprConsent).to.equal(bidderRequest.gdprConsent);
expect(serverRequest.data.uspConsent).to.equal(bidderRequest.uspConsent);
+ expect(serverRequest.data.gppConsent).to.equal(bidderRequest.gppConsent);
expect(serverRequest.data.ortb2).to.equal(bidderRequest.ortb2);
});
});
diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js
index 1139dbf5210..1709acb465f 100755
--- a/test/spec/modules/criteoBidAdapter_spec.js
+++ b/test/spec/modules/criteoBidAdapter_spec.js
@@ -2538,49 +2538,102 @@ describe('The Criteo bidding adapter', function () {
});
it('should properly parse a bid response with FLEDGE auction configs', function () {
+ let 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',
+ };
+ let 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 response = {
body: {
ext: {
- igbid: [{
+ igi: [{
impid: 'test-bidId',
- igbuyer: [{
- origin: 'https://first-buyer-domain.com',
- buyerdata: {
- foo: 'bar',
- },
- }, {
- origin: 'https://second-buyer-domain.com',
- buyerdata: {
- foo: 'baz',
- },
+ igs: [{
+ impid: 'test-bidId',
+ bidId: 'test-bidId',
+ config: auctionConfig1
}]
}, {
impid: 'test-bidId-2',
- igbuyer: [{
- origin: 'https://first-buyer-domain.com',
- buyerdata: {
- foo: 'bar',
- },
- }, {
- origin: 'https://second-buyer-domain.com',
- buyerdata: {
- foo: 'baz',
- },
+ igs: [{
+ impid: 'test-bidId-2',
+ bidId: 'test-bidId-2',
+ config: auctionConfig2
}]
- }],
- seller: 'https://seller-domain.com',
- sellerTimeout: 500,
- sellerSignals: {
- foo: 'bar',
- perBuyerTimeout: { 'buyer1': 100, 'buyer2': 200 },
- perBuyerGroupLimits: { 'buyer1': 300, 'buyer2': 400 },
- },
- sellerSignalsPerImp: {
- 'test-bidId': {
- foo2: 'bar2',
- currency: 'USD'
- },
- },
+ }]
},
},
};
@@ -2631,87 +2684,13 @@ describe('The Criteo bidding adapter', function () {
expect(interpretedResponse.fledgeAuctionConfigs).to.have.lengthOf(2);
expect(interpretedResponse.fledgeAuctionConfigs[0]).to.deep.equal({
bidId: 'test-bidId',
- config: {
- 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: {
- '*': 50,
- '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',
- },
+ impid: 'test-bidId',
+ config: auctionConfig1,
});
expect(interpretedResponse.fledgeAuctionConfigs[1]).to.deep.equal({
bidId: 'test-bidId-2',
- config: {
- 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: {
- '*': 50,
- '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: '???'
- },
+ impid: 'test-bidId-2',
+ config: auctionConfig2,
});
});
diff --git a/test/spec/modules/debugging_mod_spec.js b/test/spec/modules/debugging_mod_spec.js
index 8c7f0e84bce..ab99ba2aa0c 100644
--- a/test/spec/modules/debugging_mod_spec.js
+++ b/test/spec/modules/debugging_mod_spec.js
@@ -103,8 +103,8 @@ describe('bid interceptor', () => {
});
describe('rule', () => {
- function matchingRule({replace, options}) {
- setRules({when: {}, then: replace, options: options});
+ function matchingRule({replace, options, paapi}) {
+ setRules({when: {}, then: replace, options: options, paapi});
return interceptor.match({});
}
@@ -164,6 +164,24 @@ describe('bid interceptor', () => {
});
});
+ describe('paapi', () => {
+ it('should accept literals', () => {
+ const mockConfig = [
+ {paapi: 1},
+ {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;
+ })
+ })
+
describe('.options', () => {
it('should include default rule options', () => {
const optDef = {someOption: 'value'};
@@ -181,16 +199,17 @@ describe('bid interceptor', () => {
});
describe('intercept()', () => {
- let done, addBid;
+ let done, addBid, addPaapiConfig;
function intercept(args = {}) {
const bidRequest = {bids: args.bids || []};
- return interceptor.intercept(Object.assign({bidRequest, done, addBid}, args));
+ return interceptor.intercept(Object.assign({bidRequest, done, addBid, addPaapiConfig}, args));
}
beforeEach(() => {
done = sinon.spy();
addBid = sinon.spy();
+ addPaapiConfig = sinon.spy();
});
describe('on no match', () => {
@@ -253,6 +272,29 @@ describe('bid interceptor', () => {
});
});
+ it('should call addPaapiConfigs when provided', () => {
+ const mockPaapiConfigs = [
+ {paapi: 1},
+ {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},
+ then: null
+ });
+ intercept({bidRequest: REQUEST});
+ sinon.assert.notCalled(addBid);
+ })
+
it('should call done()', () => {
intercept({bidRequest: REQUEST});
expect(done.calledOnce).to.be.true;
diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js
index 961ccb33c4f..f1475ec3739 100644
--- a/test/spec/modules/discoveryBidAdapter_spec.js
+++ b/test/spec/modules/discoveryBidAdapter_spec.js
@@ -88,6 +88,22 @@ describe('discovery:BidAdapterTests', function () {
bidderWinsCount: 0,
},
],
+ ortb2: {
+ user: {
+ data: {
+ segment: [
+ {
+ id: '412'
+ }
+ ],
+ name: 'test.popin.cc',
+ ext: {
+ segclass: '1',
+ segtax: 503
+ }
+ }
+ }
+ }
};
let request = [];
@@ -189,6 +205,13 @@ describe('discovery:BidAdapterTests', function () {
let req_data = JSON.parse(request.data);
expect(req_data.imp).to.have.lengthOf(1);
});
+ describe('first party data', function () {
+ it('should pass additional parameter in request for topics', function () {
+ const request = spec.buildRequests(bidRequestData.bids, bidRequestData);
+ let res = JSON.parse(request.data);
+ expect(res.ext.tpData).to.deep.equal(bidRequestData.ortb2.user.data);
+ });
+ });
describe('discovery: buildRequests', function() {
describe('getPmgUID function', function() {
@@ -219,7 +242,7 @@ describe('discovery:BidAdapterTests', function () {
storage.getCookie.callsFake(() => 'existing-uuid');
const uid = getPmgUID();
expect(uid).to.equal('existing-uuid');
- expect(storage.setCookie.called).to.be.false;
+ expect(storage.setCookie.called).to.be.true;
});
it('should not set new UUID when cookies are not enabled', () => {
diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js
index b27775bb887..e1f2394ab27 100644
--- a/test/spec/modules/eids_spec.js
+++ b/test/spec/modules/eids_spec.js
@@ -29,6 +29,18 @@ describe('eids array generation for known sub-modules', function() {
});
});
+ it('unifiedId: ext generation with provider', function() {
+ const userId = {
+ tdid: {'id': 'some-sample_id', 'ext': {'provider': 'some.provider.com'}}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'adserver.org',
+ uids: [{id: 'some-sample_id', atype: 1, ext: { rtiPartner: 'TDID', provider: 'some.provider.com' }}]
+ });
+ });
+
describe('id5Id', function() {
it('does not include an ext if not provided', function() {
const userId = {
@@ -403,39 +415,6 @@ describe('eids array generation for known sub-modules', function() {
});
});
- it('thetradedesk', function() {
- const userId = {
- thetradedesk: {'id': 'sample_id'}
- };
- const newEids = createEidsArray(userId);
- expect(newEids.length).to.equal(1);
- expect(newEids[0]).to.deep.equal({
- source: 'adserver.org',
- uids: [{
- id: 'sample_id',
- atype: 3
- }]
- });
- });
-
- it('thetradedesk with ext', function() {
- const userId = {
- thetradedesk: {'id': 'sample_id', 'ext': {'provider': 'some.provider.com'}}
- };
- const newEids = createEidsArray(userId);
- expect(newEids.length).to.equal(1);
- expect(newEids[0]).to.deep.equal({
- source: 'adserver.org',
- uids: [{
- id: 'sample_id',
- atype: 3,
- ext: {
- provider: 'some.provider.com'
- }
- }]
- });
- });
-
it('liveIntentId; getValue call and NO ext', function() {
const userId = {
lipb: {
diff --git a/test/spec/modules/enrichmentFpdModule_spec.js b/test/spec/modules/enrichmentFpdModule_spec.js
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/test/spec/modules/hypelabBidAdapter_spec.js b/test/spec/modules/hypelabBidAdapter_spec.js
index 4522073a2db..28d0739de79 100644
--- a/test/spec/modules/hypelabBidAdapter_spec.js
+++ b/test/spec/modules/hypelabBidAdapter_spec.js
@@ -92,7 +92,7 @@ const mockBidRequest = {
placement_slug: 'test_placement',
provider_version: '0.0.1',
provider_name: 'prebid',
- referrer: 'https://example.com',
+ location: 'https://example.com',
sdk_version: '7.51.0-pre',
sizes: [[728, 90]],
wids: [],
@@ -160,6 +160,9 @@ describe('hypelabBidAdapter', function () {
expect(data.bidRequestsCount).to.be.a('number');
expect(data.bidderRequestsCount).to.be.a('number');
expect(data.bidderWinsCount).to.be.a('number');
+ expect(data.dpr).to.be.a('number');
+ expect(data.location).to.be.a('string');
+ expect(data.floor).to.equal(null);
});
describe('should set uuid to the first id in userIdAsEids', () => {
@@ -211,6 +214,7 @@ describe('hypelabBidAdapter', function () {
expect(data.ad).to.be.a('string');
expect(data.mediaType).to.be.a('string');
expect(data.meta.advertiserDomains).to.be.an('array');
+ expect(data.meta.advertiserDomains[0]).to.be.a('string');
});
describe('should return a blank array if cpm is not set', () => {
diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js
index ecce98d0b8d..af468f2fe4d 100644
--- a/test/spec/modules/id5IdSystem_spec.js
+++ b/test/spec/modules/id5IdSystem_spec.js
@@ -1,5 +1,11 @@
import * as id5System from '../../../modules/id5IdSystem.js';
-import {coreStorage, getConsentHash, init, requestBidsHook, setSubmoduleRegistry} from '../../../modules/userId/index.js';
+import {
+ coreStorage,
+ getConsentHash,
+ init,
+ requestBidsHook,
+ setSubmoduleRegistry
+} from '../../../modules/userId/index.js';
import {config} from '../../../src/config.js';
import * as events from '../../../src/events.js';
import CONSTANTS from '../../../src/constants.json';
@@ -10,7 +16,7 @@ import {hook} from '../../../src/hook.js';
import {mockGdprConsent} from '../../helpers/consentData.js';
import {server} from '../../mocks/xhr.js';
import {expect} from 'chai';
-import { GreedyPromise } from '../../../src/utils/promise.js';
+import {GreedyPromise} from '../../../src/utils/promise.js';
const IdFetchFlow = id5System.IdFetchFlow;
@@ -37,6 +43,22 @@ describe('ID5 ID System', function () {
'linkType': ID5_STORED_LINK_TYPE
}
};
+ const EUID_STORED_ID = 'EUID_1';
+ const EUID_SOURCE = 'uidapi.com';
+ const ID5_STORED_OBJ_WITH_EUID = {
+ 'universal_uid': ID5_STORED_ID,
+ 'signature': ID5_STORED_SIGNATURE,
+ 'ext': {
+ 'linkType': ID5_STORED_LINK_TYPE,
+ 'euid': {
+ 'source': EUID_SOURCE,
+ 'uids': [{
+ 'id': EUID_STORED_ID,
+ 'aType': 3
+ }]
+ }
+ }
+ };
const ID5_RESPONSE_ID = 'newid5id';
const ID5_RESPONSE_SIGNATURE = 'abcdef';
const ID5_RESPONSE_LINK_TYPE = 2;
@@ -886,6 +908,35 @@ describe('ID5 ID System', function () {
}, {adUnits});
});
+ it('should add stored EUID from cache to bids', function (done) {
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ_WITH_EUID), 1);
+
+ init(config);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
+ config.setConfig(getFetchLocalStorageConfig());
+
+ requestBidsHook(function () {
+ adUnits.forEach(unit => {
+ unit.bids.forEach(bid => {
+ expect(bid).to.have.deep.nested.property(`userId.euid`);
+ expect(bid.userId.euid.uid).is.equal(EUID_STORED_ID);
+ expect(bid.userIdAsEids[0].uids[0].id).is.equal(ID5_STORED_ID);
+ expect(bid.userIdAsEids[1]).is.deep.equal({
+ source: EUID_SOURCE,
+ uids: [{
+ id: EUID_STORED_ID,
+ atype: 3,
+ ext: {
+ provider: ID5_SOURCE
+ }
+ }]
+ })
+ });
+ });
+ done();
+ }, {adUnits});
+ });
+
it('should add config value ID to bids', function (done) {
init(config);
setSubmoduleRegistry([id5System.id5IdSubmodule]);
@@ -984,6 +1035,13 @@ describe('ID5 ID System', function () {
it('should return undefined if passed a string', function () {
expect(id5System.id5IdSubmodule.decode('somestring', getId5FetchConfig())).is.eq(undefined);
});
+ it('should decode euid from a stored object with EUID', function () {
+ expect(id5System.id5IdSubmodule.decode(ID5_STORED_OBJ_WITH_EUID, getId5FetchConfig()).euid).is.deep.equal({
+ 'source': EUID_SOURCE,
+ 'uid': EUID_STORED_ID,
+ 'ext': {'provider': ID5_SOURCE}
+ });
+ });
});
describe('A/B Testing', function () {
diff --git a/test/spec/modules/jixieBidAdapter_spec.js b/test/spec/modules/jixieBidAdapter_spec.js
index fa7618814f8..5428fd0db0f 100644
--- a/test/spec/modules/jixieBidAdapter_spec.js
+++ b/test/spec/modules/jixieBidAdapter_spec.js
@@ -707,4 +707,67 @@ describe('jixie Adapter', function () {
expect(jixieaux.ajax.calledWith(TRACKINGURL_)).to.equal(true);
})
}); // describe
+
+ describe('getUserSyncs', function () {
+ it('it should favour iframe over pixel if publisher allows iframe usersync', function () {
+ const syncOptions = {
+ 'iframeEnabled': true,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ 'up': 'https://syncstuff.jixie.io/image.gif'
+ },
+ {
+ 'up': 'https://syncstuff.jixie.io/image1.gif'
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result[0].type).to.equal('iframe')
+ expect(result[1].type).to.equal('image')
+ })
+
+ it('it should pick pixel if publisher not allow iframe', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ 'up': 'https://syncstuff.jixie.io/image.gif'
+ },
+ {
+ 'up': 'https://syncstuff.jixie.io/image1.gif'
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result[0].type).to.equal('image')
+ expect(result[1].type).to.equal('image')
+ })
+
+ it('it should return nothing if pub only allow pixel but all usersyncs are iframe only', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ },
+ {
+ 'uf': 'https://syncstuff2.jixie.io/',
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result.length).to.equal(0)
+ })
+ })
});
diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js
index 4638595e0d6..12fe9a7e800 100644
--- a/test/spec/modules/jwplayerRtdProvider_spec.js
+++ b/test/spec/modules/jwplayerRtdProvider_spec.js
@@ -237,6 +237,41 @@ describe('jwplayerRtdProvider', function() {
fetchTargetingForMediaId(mediaIdWithSegment);
+ const bid = {};
+ const adUnit = {
+ ortb2Imp: {
+ ext: {
+ data: {
+ jwTargeting: {
+ mediaID: mediaIdWithSegment,
+ playerDivId: validPlayerID
+ }
+ }
+ }
+ },
+ bids: [
+ bid
+ ]
+ };
+ const expectedContentId = 'jw_' + mediaIdWithSegment;
+ const expectedTargeting = {
+ segments: validSegments,
+ content: {
+ id: expectedContentId
+ }
+ };
+ jwplayerSubmodule.getBidRequestData({ adUnits: [adUnit] }, bidRequestSpy);
+ expect(bidRequestSpy.calledOnce).to.be.true;
+ expect(bid.rtd.jwplayer).to.have.deep.property('targeting', expectedTargeting);
+ server.respond();
+ expect(bidRequestSpy.calledOnce).to.be.true;
+ });
+
+ it('includes backwards support for playerID when playerDivId is not set', function () {
+ const bidRequestSpy = sinon.spy();
+
+ fetchTargetingForMediaId(mediaIdWithSegment);
+
const bid = {};
const adUnit = {
ortb2Imp: {
@@ -605,23 +640,23 @@ describe('jwplayerRtdProvider', function() {
it('should prioritize adUnit properties ', function () {
const expectedMediaID = 'test_media_id';
const expectedPlayerID = 'test_player_id';
- const config = { playerID: 'bad_id', mediaID: 'bad_id' };
+ const config = { playerDivId: 'bad_id', mediaID: 'bad_id' };
- const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID, playerID: expectedPlayerID } } } } };
+ const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID, playerDivId: expectedPlayerID } } } } };
const targeting = extractPublisherParams(adUnit, config);
expect(targeting).to.have.property('mediaID', expectedMediaID);
- expect(targeting).to.have.property('playerID', expectedPlayerID);
+ expect(targeting).to.have.property('playerDivId', expectedPlayerID);
});
it('should use config properties as fallbacks', function () {
const expectedMediaID = 'test_media_id';
const expectedPlayerID = 'test_player_id';
- const config = { playerID: expectedPlayerID, mediaID: 'bad_id' };
+ const config = { playerDivId: expectedPlayerID, mediaID: 'bad_id' };
const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID } } } } };
const targeting = extractPublisherParams(adUnit, config);
expect(targeting).to.have.property('mediaID', expectedMediaID);
- expect(targeting).to.have.property('playerID', expectedPlayerID);
+ expect(targeting).to.have.property('playerDivId', expectedPlayerID);
});
it('should return undefined when Publisher Params are absent', function () {
diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js
index f43c3b11aac..20a43d0397f 100644
--- a/test/spec/modules/kargoBidAdapter_spec.js
+++ b/test/spec/modules/kargoBidAdapter_spec.js
@@ -479,6 +479,21 @@ describe('kargo adapter tests', function () {
floor: 1,
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '10101',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
}
},
{
@@ -491,6 +506,21 @@ describe('kargo adapter tests', function () {
},
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ floor: 2,
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '20202',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
+ }
}
},
{
@@ -503,6 +533,21 @@ describe('kargo adapter tests', function () {
},
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ floor: 3,
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '30303',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ },
+ gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
}
}
],
@@ -553,6 +598,56 @@ describe('kargo adapter tests', function () {
]
}
]
+ },
+ ext: {
+ ortb2: {
+ device: {
+ sua: {
+ platform: {
+ brand: 'macOS',
+ version: ['12', '6', '0']
+ },
+ browsers: [
+ {
+ brand: 'Chromium',
+ version: ['106', '0', '5249', '119']
+ },
+ {
+ brand: 'Google Chrome',
+ version: ['106', '0', '5249', '119']
+ },
+ {
+ brand: 'Not;A=Brand',
+ version: ['99', '0', '0', '0']
+ }
+ ],
+ mobile: 1,
+ model: 'model',
+ source: 1,
+ }
+ },
+ site: {
+ id: '1234',
+ name: 'SiteName',
+ cat: ['IAB1', 'IAB2', 'IAB3']
+ },
+ user: {
+ data: [
+ {
+ name: 'prebid.org',
+ ext: {
+ segtax: 600,
+ segclass: 'v1',
+ },
+ segment: [
+ {
+ id: '133'
+ },
+ ]
+ },
+ ]
+ }
+ }
}
};
@@ -605,6 +700,16 @@ describe('kargo adapter tests', function () {
payload['gdprConsent'] = gdpr
}
+ clonedBids.forEach(bid => {
+ if (bid.mediaTypes.banner) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 1 });
+ } else if (bid.mediaTypes.video) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 2 });
+ } else if (bid.mediaTypes.native) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 3 });
+ }
+ });
+
var request = spec.buildRequests(clonedBids, payload);
var krakenParams = request.data;
@@ -725,7 +830,8 @@ describe('kargo adapter tests', function () {
adm: '',
width: 320,
height: 50,
- metadata: {}
+ metadata: {},
+ creativeID: 'bar'
},
2: {
id: 'bar',
@@ -736,14 +842,16 @@ describe('kargo adapter tests', function () {
targetingCustom: 'dmpmptest1234',
metadata: {
landingPageDomain: ['https://foobar.com']
- }
+ },
+ creativeID: 'foo'
},
3: {
id: 'bar',
cpm: 2.5,
adm: '',
width: 300,
- height: 250
+ height: 250,
+ creativeID: 'foo'
},
4: {
id: 'bar',
@@ -753,6 +861,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'banner',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
},
5: {
@@ -763,6 +872,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'video',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
},
6: {
@@ -774,6 +884,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'video',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
}
}
@@ -818,7 +929,7 @@ describe('kargo adapter tests', function () {
width: 320,
height: 50,
ttl: 300,
- creativeId: 'foo',
+ creativeId: 'bar',
dealId: undefined,
netRevenue: true,
currency: 'USD',
@@ -833,7 +944,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: 'dmpmptest1234',
netRevenue: true,
currency: 'USD',
@@ -850,7 +961,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'USD',
@@ -865,7 +976,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
@@ -880,7 +991,7 @@ describe('kargo adapter tests', function () {
height: 250,
vastXml: '',
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
@@ -895,7 +1006,7 @@ describe('kargo adapter tests', function () {
height: 250,
vastUrl: 'https://foobar.com/vast_adm',
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
diff --git a/test/spec/modules/liveIntentIdMinimalSystem_spec.js b/test/spec/modules/liveIntentIdMinimalSystem_spec.js
index 6002e827593..e280d9108a0 100644
--- a/test/spec/modules/liveIntentIdMinimalSystem_spec.js
+++ b/test/spec/modules/liveIntentIdMinimalSystem_spec.js
@@ -294,7 +294,7 @@ describe('LiveIntentMinimalId', function() {
const provider = 'liveintent.com'
refererInfoStub.returns({domain: provider})
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' });
- expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'thetradedesk': 'bar'}, 'thetradedesk': {'id': 'bar', 'ext': {'provider': provider}}});
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'tdid': 'bar'}, 'tdid': {'id': 'bar', 'ext': {'rtiPartner': 'TDID', 'provider': provider}}});
});
it('should allow disabling nonId resolution', function() {
diff --git a/test/spec/modules/liveIntentIdSystem_spec.js b/test/spec/modules/liveIntentIdSystem_spec.js
index 23f7bcda36b..c6108b49715 100644
--- a/test/spec/modules/liveIntentIdSystem_spec.js
+++ b/test/spec/modules/liveIntentIdSystem_spec.js
@@ -432,7 +432,7 @@ describe('LiveIntentId', function() {
const provider = 'liveintent.com'
refererInfoStub.returns({domain: provider})
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' });
- expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'thetradedesk': 'bar'}, 'thetradedesk': {'id': 'bar', 'ext': {'provider': provider}}});
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'tdid': 'bar'}, 'tdid': {'id': 'bar', 'ext': {'rtiPartner': 'TDID', 'provider': provider}}});
});
it('should allow disabling nonId resolution', function() {
diff --git a/test/spec/modules/luceadBidAdapter_spec.js b/test/spec/modules/luceadBidAdapter_spec.js
index fa8d76cc30b..72bc7cc2d6e 100644
--- a/test/spec/modules/luceadBidAdapter_spec.js
+++ b/test/spec/modules/luceadBidAdapter_spec.js
@@ -15,6 +15,12 @@ describe('Lucead Adapter', () => {
});
});
+ describe('utils functions', function () {
+ it('returns false', function () {
+ expect(spec.isDevEnv()).to.be.false;
+ });
+ });
+
describe('isBidRequestValid', function () {
let bid;
beforeEach(function () {
@@ -33,7 +39,7 @@ describe('Lucead Adapter', () => {
describe('onBidWon', function () {
let sandbox;
- const bid = { foo: 'bar' };
+ const bid = { foo: 'bar', creativeId: 'ssp:improve' };
beforeEach(function () {
sandbox = sinon.sandbox.create();
diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js
index 0dfd6c15ba8..397ee4a8577 100644
--- a/test/spec/modules/magniteAnalyticsAdapter_spec.js
+++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js
@@ -1741,6 +1741,79 @@ describe('magnite analytics adapter', function () {
expect(message1.bidsWon).to.deep.equal([expectedMessage1]);
});
});
+ describe('cookieless', () => {
+ beforeEach(() => {
+ magniteAdapter.enableAnalytics({
+ options: {
+ cookieles: undefined
+ }
+ });
+ })
+ afterEach(() => {
+ magniteAdapter.disableAnalytics();
+ })
+ it('should add sufix _cookieless to the wrapper.rule if ortb2.device.ext.cdep start with "treatment" or "control_2"', () => {
+ // Set the confs
+ config.setConfig({
+ rubicon: {
+ wrapperName: '1001_general',
+ wrapperFamily: 'general',
+ rule_name: 'desktop-magnite.com',
+ }
+ });
+ const auctionId = MOCK.AUCTION_INIT.auctionId;
+
+ let auctionInit = utils.deepClone(MOCK.AUCTION_INIT);
+ auctionInit.bidderRequests[0].ortb2.device.ext = { cdep: 'treatment' };
+ // Run auction
+ events.emit(AUCTION_INIT, auctionInit);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+ events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ [gptSlotRenderEnded0].forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params));
+ events.emit(BID_WON, { ...MOCK.BID_WON, auctionId });
+ clock.tick(rubiConf.analyticsEventDelay);
+ expect(server.requests.length).to.equal(1);
+ let request = server.requests[0];
+ let message = JSON.parse(request.requestBody);
+ expect(message.wrapper).to.deep.equal({
+ name: '1001_general',
+ family: 'general',
+ rule: 'desktop-magnite.com_cookieless',
+ });
+ })
+ it('should add cookieless to the wrapper.rule if ortb2.device.ext.cdep start with "treatment" or "control_2"', () => {
+ // Set the confs
+ config.setConfig({
+ rubicon: {
+ wrapperName: '1001_general',
+ wrapperFamily: 'general',
+ }
+ });
+ const auctionId = MOCK.AUCTION_INIT.auctionId;
+
+ let auctionInit = utils.deepClone(MOCK.AUCTION_INIT);
+ auctionInit.bidderRequests[0].ortb2.device.ext = { cdep: 'control_2' };
+ // Run auction
+ events.emit(AUCTION_INIT, auctionInit);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+ events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ [gptSlotRenderEnded0].forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params));
+ events.emit(BID_WON, { ...MOCK.BID_WON, auctionId });
+ clock.tick(rubiConf.analyticsEventDelay);
+ expect(server.requests.length).to.equal(1);
+ let request = server.requests[0];
+ let message = JSON.parse(request.requestBody);
+ expect(message.wrapper).to.deep.equal({
+ family: 'general',
+ name: '1001_general',
+ rule: 'cookieless',
+ });
+ });
+ });
});
describe('billing events integration', () => {
diff --git a/test/spec/modules/mediaimpactBidAdapter_spec.js b/test/spec/modules/mediaimpactBidAdapter_spec.js
new file mode 100644
index 00000000000..3d706e59c3f
--- /dev/null
+++ b/test/spec/modules/mediaimpactBidAdapter_spec.js
@@ -0,0 +1,336 @@
+import {expect} from 'chai';
+import {spec, ENDPOINT_PROTOCOL, ENDPOINT_DOMAIN, ENDPOINT_PATH} from 'modules/mediaimpactBidAdapter.js';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+
+const BIDDER_CODE = 'mediaimpact';
+
+describe('MediaimpactAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.be.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ it('should return true when required params found', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': 123
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(true);
+ });
+
+ it('should return true when required params is srting', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': '456'
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(true);
+ });
+
+ it('should return false when required params are not passed', function () {
+ let validRequest = {
+ 'params': {
+ 'unknownId': 123
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(false);
+ });
+
+ it('should return false when required params is 0', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': 0
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ let validEndpoint = ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&partner=777&sizes=300x250|300x600,728x90,300x250&referer=https%3A%2F%2Ftest.domain';
+
+ let validRequest = [
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'unitId': 123
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e'
+ },
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'unitId': '456'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '22aidtbx5eabd9'
+ },
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'partnerId': 777
+ },
+ 'adUnitCode': 'partner-code-3',
+ 'sizes': [[300, 250]],
+ 'bidId': '5d4531d5a6c013'
+ }
+ ];
+
+ let bidderRequest = {
+ refererInfo: {
+ page: 'https://test.domain'
+ }
+ };
+
+ it('bidRequest HTTP method', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('bidRequest url', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ expect(request.url).to.equal(validEndpoint);
+ });
+
+ it('bidRequest data', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ const payload = JSON.parse(request.data);
+ expect(payload[0].unitId).to.equal(123);
+ expect(payload[0].sizes).to.deep.equal([[300, 250], [300, 600]]);
+ expect(payload[0].bidId).to.equal('30b31c1838de1e');
+ expect(payload[1].unitId).to.equal(456);
+ expect(payload[1].sizes).to.deep.equal([[728, 90]]);
+ expect(payload[1].bidId).to.equal('22aidtbx5eabd9');
+ expect(payload[2].partnerId).to.equal(777);
+ expect(payload[2].sizes).to.deep.equal([[300, 250]]);
+ expect(payload[2].bidId).to.equal('5d4531d5a6c013');
+ });
+ });
+
+ describe('joinSizesToString', function () {
+ it('success convert sizes list to string', function () {
+ const sizesStr = spec.joinSizesToString([[300, 250], [300, 600]]);
+ expect(sizesStr).to.equal('300x250|300x600');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const bidRequest = {
+ 'method': 'POST',
+ 'url': ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&partner=777code=adunit-code-1,adunit-code-2,partner-code-3&bid=30b31c1838de1e,22aidtbx5eabd9,5d4531d5a6c013&sizes=300x250|300x600,728x90,300x250&referer=https%3A%2F%2Ftest.domain',
+ 'data': '[{"unitId": 13144370,"adUnitCode": "div-gpt-ad-1460505748561-0","sizes": [[300, 250], [300, 600]],"bidId": "2bdcb0b203c17d","referer": "https://test.domain/index.html"},' +
+ '{"unitId": 13144370,"adUnitCode":"div-gpt-ad-1460505748561-1","sizes": [[768, 90]],"bidId": "3dc6b8084f91a8","referer": "https://test.domain/index.html"},' +
+ '{"unitId": 0,"partnerId": 777,"adUnitCode":"div-gpt-ad-1460505748561-2","sizes": [[300, 250]],"bidId": "5d4531d5a6c013","referer": "https://test.domain/index.html"}]'
+ };
+
+ const bidResponse = {
+ body: {
+ 'div-gpt-ad-1460505748561-0':
+ {
+ 'ad': 'ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'adomain': [
+ 'test.domain'
+ ],
+ 'syncs': [
+ {'type': 'image', 'url': 'https://test.domain/tracker_1.gif'},
+ {'type': 'image', 'url': 'https://test.domain/tracker_2.gif'},
+ {'type': 'image', 'url': 'https://test.domain/tracker_3.gif'}
+ ],
+ 'winNotification': [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true
+ }
+ },
+ headers: {}
+ };
+
+ it('result is correct', function () {
+ const result = spec.interpretResponse(bidResponse, bidRequest);
+ expect(result[0].requestId).to.equal('2bdcb0b203c17d');
+ expect(result[0].cpm).to.equal(0.01);
+ expect(result[0].width).to.equal(300);
+ expect(result[0].height).to.equal(250);
+ expect(result[0].creativeId).to.equal('8:123456');
+ expect(result[0].currency).to.equal('USD');
+ expect(result[0].ttl).to.equal(60);
+ expect(result[0].meta.advertiserDomains).to.deep.equal(['test.domain']);
+ expect(result[0].winNotification[0]).to.deep.equal({'method': 'POST', 'path': '/hb/bid_won?test=1', 'data': {'ad': [{'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}], 'unit_id': 1234, 'site_id': 123}});
+ });
+ });
+
+ describe('adResponse', function () {
+ const bid = {
+ 'unitId': 13144370,
+ 'adUnitCode': 'div-gpt-ad-1460505748561-0',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '2bdcb0b203c17d',
+ 'referer': 'https://test.domain/index.html'
+ };
+ const ad = {
+ 'ad': 'ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'syncs': [],
+ 'winNotification': [],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'adomain': [
+ 'test.domain'
+ ],
+ };
+
+ it('fill ad for response', function () {
+ const result = spec.adResponse(bid, ad);
+ expect(result.requestId).to.equal('2bdcb0b203c17d');
+ expect(result.cpm).to.equal(0.01);
+ expect(result.width).to.equal(300);
+ expect(result.height).to.equal(250);
+ expect(result.creativeId).to.equal('8:123456');
+ expect(result.currency).to.equal('USD');
+ expect(result.ttl).to.equal(60);
+ expect(result.meta.advertiserDomains).to.deep.equal(['test.domain']);
+ });
+ });
+
+ describe('onBidWon', function () {
+ const bid = {
+ winNotification: [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 0.01, 'nurl': 'http://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ]
+ };
+
+ let ajaxStub;
+
+ beforeEach(() => {
+ ajaxStub = sinon.stub(spec, 'postRequest')
+ })
+
+ afterEach(() => {
+ ajaxStub.restore()
+ })
+
+ it('calls mediaimpact callback endpoint', () => {
+ const result = spec.onBidWon(bid);
+ expect(result).to.equal(true);
+ expect(ajaxStub.calledOnce).to.equal(true);
+ expect(ajaxStub.firstCall.args[0]).to.equal(ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + '/hb/bid_won?test=1');
+ expect(ajaxStub.firstCall.args[1]).to.deep.equal(JSON.stringify(bid.winNotification[0].data));
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ const bidResponse = [{
+ body: {
+ 'div-gpt-ad-1460505748561-0':
+ {
+ 'ad': 'ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'adomain': [
+ 'test.domain'
+ ],
+ 'syncs': [
+ {'type': 'image', 'link': 'https://test.domain/tracker_1.gif'},
+ {'type': 'image', 'link': 'https://test.domain/tracker_2.gif'},
+ {'type': 'image', 'link': 'https://test.domain/tracker_3.gif'}
+ ],
+ 'winNotification': [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true
+ }
+ },
+ headers: {}
+ }];
+
+ it('should return nothing when sync is disabled', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': false
+ };
+
+ let syncs = spec.getUserSyncs(syncOptions);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should register image sync when only image is enabled where gdprConsent is undefined', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true
+ };
+
+ const gdprConsent = undefined;
+ let syncs = spec.getUserSyncs(syncOptions, bidResponse, gdprConsent);
+ expect(syncs.length).to.equal(3);
+ expect(syncs[0].type).to.equal('image');
+ expect(syncs[0].url).to.equal('https://test.domain/tracker_1.gif');
+ });
+
+ it('should register image sync when only image is enabled where gdprConsent is defined', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true
+ };
+ const gdprConsent = {
+ consentString: 'someString',
+ vendorData: {},
+ gdprApplies: true,
+ apiVersion: 2
+ };
+
+ let syncs = spec.getUserSyncs(syncOptions, bidResponse, gdprConsent);
+ expect(syncs.length).to.equal(3);
+ expect(syncs[0].type).to.equal('image');
+ expect(syncs[0].url).to.equal('https://test.domain/tracker_1.gif?gdpr=1&gdpr_consent=someString');
+ });
+ });
+});
diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js
index b9871bbbe71..ff58671b17b 100644
--- a/test/spec/modules/nextMillenniumBidAdapter_spec.js
+++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js
@@ -34,7 +34,7 @@ describe('nextMillenniumBidAdapterTests', () => {
bidfloorcur: 'EUR',
bidfloor: 1.11,
ext: {prebid: {storedrequest: {id: '123'}}},
- banner: {format: [{w: 300, h: 250}, {w: 320, h: 250}]},
+ banner: {w: 300, h: 250, format: [{w: 300, h: 250}, {w: 320, h: 250}]},
},
},
@@ -43,13 +43,13 @@ describe('nextMillenniumBidAdapterTests', () => {
data: {
id: '234',
bid: {
- mediaTypes: {video: {playerSize: [400, 300]}},
+ mediaTypes: {video: {playerSize: [400, 300], api: [2], placement: 1, plcmt: 1}},
adUnitCode: 'test-video-1',
},
mediaTypes: {
video: {
- data: {playerSize: [400, 300]},
+ data: {playerSize: [400, 300], api: [2], placement: 1, plcmt: 1},
bidfloorcur: 'USD',
},
},
@@ -59,7 +59,39 @@ describe('nextMillenniumBidAdapterTests', () => {
id: 'test-video-1',
bidfloorcur: 'USD',
ext: {prebid: {storedrequest: {id: '234'}}},
- video: {w: 400, h: 300},
+ video: {
+ mimes: ['video/mp4', 'video/x-ms-wmv', 'application/javascript'],
+ api: [2],
+ placement: 1,
+ plcmt: 1,
+ w: 400,
+ h: 300,
+ },
+ },
+ },
+
+ {
+ title: 'imp - mediaTypes.video is empty',
+ data: {
+ id: '234',
+ bid: {
+ mediaTypes: {video: {w: 640, h: 480}},
+ adUnitCode: 'test-video-2',
+ },
+
+ mediaTypes: {
+ video: {
+ data: {w: 640, h: 480},
+ bidfloorcur: 'USD',
+ },
+ },
+ },
+
+ expected: {
+ id: 'test-video-2',
+ bidfloorcur: 'USD',
+ ext: {prebid: {storedrequest: {id: '234'}}},
+ video: {w: 640, h: 480, mimes: ['video/mp4', 'video/x-ms-wmv', 'application/javascript']},
},
},
];
@@ -902,7 +934,7 @@ describe('nextMillenniumBidAdapterTests', () => {
];
for (let {eventName, bid, expected} of dataForTests) {
- const url = spec.getUrlPixelMetric(eventName, bid);
+ const url = spec._getUrlPixelMetric(eventName, bid);
expect(url).to.equal(expected);
};
})
diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js
index 7091bb56631..f18e0365226 100644
--- a/test/spec/modules/nexx360BidAdapter_spec.js
+++ b/test/spec/modules/nexx360BidAdapter_spec.js
@@ -20,12 +20,12 @@ const instreamResponse = {
'crid': '97517771',
'h': 1,
'w': 1,
+ 'adm': '\n \n \n Nexx360 Wrapper\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ',
'ext': {
'mediaType': 'instream',
'ssp': 'appnexus',
'divId': 'video1',
'adUnitCode': 'video1',
- 'vastXml': '\n \n \n Nexx360 Wrapper\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '
}
}
],
@@ -374,7 +374,7 @@ describe('Nexx360 bid adapter tests', function () {
expect(requestContent.imp[1].tagid).to.be.eql('div-2-abcd');
expect(requestContent.imp[1].ext.adUnitCode).to.be.eql('div-2-abcd');
expect(requestContent.imp[1].ext.divId).to.be.eql('div-2-abcd');
- expect(requestContent.ext.bidderVersion).to.be.eql('3.0');
+ expect(requestContent.ext.bidderVersion).to.be.eql('4.0');
expect(requestContent.ext.source).to.be.eql('prebid.js');
});
@@ -561,7 +561,7 @@ describe('Nexx360 bid adapter tests', function () {
}
};
const output = spec.interpretResponse(response);
- expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].ext.vastXml);
+ expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].adm);
expect(output[0].mediaType).to.be.eql('video');
expect(output[0].currency).to.be.eql(response.body.cur);
expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price);
@@ -585,11 +585,11 @@ describe('Nexx360 bid adapter tests', function () {
'crid': '97517771',
'h': 1,
'w': 1,
+ 'adm': '\n \n \n Nexx360 Wrapper\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ',
'ext': {
'mediaType': 'outstream',
'ssp': 'appnexus',
'adUnitCode': 'div-1',
- 'vastXml': '\n \n \n Nexx360 Wrapper\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '
}
}
],
@@ -602,7 +602,7 @@ describe('Nexx360 bid adapter tests', function () {
}
};
const output = spec.interpretResponse(response);
- expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].ext.vastXml);
+ expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].adm);
expect(output[0].mediaType).to.be.eql('video');
expect(output[0].currency).to.be.eql(response.body.cur);
expect(typeof output[0].renderer).to.be.eql('object');
diff --git a/test/spec/modules/nobidAnalyticsAdapter_spec.js b/test/spec/modules/nobidAnalyticsAdapter_spec.js
index 3da334eea97..f6c741bb7ff 100644
--- a/test/spec/modules/nobidAnalyticsAdapter_spec.js
+++ b/test/spec/modules/nobidAnalyticsAdapter_spec.js
@@ -127,9 +127,9 @@ describe('NoBid Prebid Analytic', function () {
mediaType: 'banner',
source: 'client',
cpm: 6.4,
+ currency: 'EUR',
creativeId: 'TEST',
dealId: '',
- currency: 'USD',
netRevenue: true,
ttl: 300,
ad: 'AD HERE',
@@ -167,13 +167,17 @@ describe('NoBid Prebid Analytic', function () {
]
};
- const requestOutgoing = {
+ const expectedOutgoingRequest = {
+ version: nobidAnalyticsVersion,
bidderCode: 'nobid',
statusMessage: 'Bid available',
adId: '106d14b7d06b607',
requestId: '67a7f0e7ea55c4',
mediaType: 'banner',
cpm: 6.4,
+ currency: 'EUR',
+ originalCpm: 6.44,
+ originalCurrency: 'USD',
adUnitCode: 'leaderboard',
timeToRespond: 545,
size: '728x90',
@@ -197,16 +201,20 @@ describe('NoBid Prebid Analytic', function () {
clock.tick(5000);
expect(server.requests).to.have.length(1);
const bidWonRequest = JSON.parse(server.requests[0].requestBody);
- expect(bidWonRequest).to.have.property('bidderCode', requestOutgoing.bidderCode);
- expect(bidWonRequest).to.have.property('statusMessage', requestOutgoing.statusMessage);
- expect(bidWonRequest).to.have.property('adId', requestOutgoing.adId);
- expect(bidWonRequest).to.have.property('requestId', requestOutgoing.requestId);
- expect(bidWonRequest).to.have.property('mediaType', requestOutgoing.mediaType);
- expect(bidWonRequest).to.have.property('cpm', requestOutgoing.cpm);
- expect(bidWonRequest).to.have.property('adUnitCode', requestOutgoing.adUnitCode);
- expect(bidWonRequest).to.have.property('timeToRespond', requestOutgoing.timeToRespond);
- expect(bidWonRequest).to.have.property('size', requestOutgoing.size);
- expect(bidWonRequest).to.have.property('topLocation', requestOutgoing.topLocation);
+ expect(bidWonRequest).to.have.property('version', nobidAnalyticsVersion);
+ expect(bidWonRequest).to.have.property('bidderCode', expectedOutgoingRequest.bidderCode);
+ expect(bidWonRequest).to.have.property('statusMessage', expectedOutgoingRequest.statusMessage);
+ expect(bidWonRequest).to.have.property('adId', expectedOutgoingRequest.adId);
+ expect(bidWonRequest).to.have.property('requestId', expectedOutgoingRequest.requestId);
+ expect(bidWonRequest).to.have.property('mediaType', expectedOutgoingRequest.mediaType);
+ expect(bidWonRequest).to.have.property('cpm', expectedOutgoingRequest.cpm);
+ expect(bidWonRequest).to.have.property('currency', expectedOutgoingRequest.currency);
+ expect(bidWonRequest).to.have.property('originalCpm', expectedOutgoingRequest.originalCpm);
+ expect(bidWonRequest).to.have.property('originalCurrency', expectedOutgoingRequest.originalCurrency);
+ expect(bidWonRequest).to.have.property('adUnitCode', expectedOutgoingRequest.adUnitCode);
+ expect(bidWonRequest).to.have.property('timeToRespond', expectedOutgoingRequest.timeToRespond);
+ expect(bidWonRequest).to.have.property('size', expectedOutgoingRequest.size);
+ expect(bidWonRequest).to.have.property('topLocation', expectedOutgoingRequest.topLocation);
expect(bidWonRequest).to.not.have.property('pbCg');
done();
@@ -304,10 +312,10 @@ describe('NoBid Prebid Analytic', function () {
auctionId: '4c056b3c-f1a6-46bd-8d82-58c15b22fcfa',
mediaType: 'banner',
source: 'client',
- cpm: 6.44,
+ cpm: 5.93,
+ currency: 'EUR',
creativeId: 'TEST',
dealId: '',
- currency: 'USD',
netRevenue: true,
ttl: 300,
ad: '',
@@ -336,7 +344,7 @@ describe('NoBid Prebid Analytic', function () {
timeout: 3000
};
- const requestOutgoing = {
+ const expectedOutgoingRequest = {
auctionId: '4c056b3c-f1a6-46bd-8d82-58c15b22fcfa',
bidderRequests: [
{
@@ -364,7 +372,10 @@ describe('NoBid Prebid Analytic', function () {
width: 728,
height: 90,
mediaType: 'banner',
- cpm: 6.44,
+ cpm: 5.93,
+ currency: 'EUR',
+ originalCpm: 6.44,
+ originalCurrency: 'USD',
adUnitCode: 'leaderboard'
}
]
@@ -387,22 +398,26 @@ describe('NoBid Prebid Analytic', function () {
clock.tick(5000);
expect(server.requests).to.have.length(1);
const auctionEndRequest = JSON.parse(server.requests[0].requestBody);
- expect(auctionEndRequest).to.have.property('auctionId', requestOutgoing.auctionId);
+ expect(auctionEndRequest).to.have.property('version', nobidAnalyticsVersion);
+ expect(auctionEndRequest).to.have.property('auctionId', expectedOutgoingRequest.auctionId);
expect(auctionEndRequest.bidderRequests).to.have.length(1);
- expect(auctionEndRequest.bidderRequests[0].bidderCode).to.equal(requestOutgoing.bidderRequests[0].bidderCode);
+ expect(auctionEndRequest.bidderRequests[0].bidderCode).to.equal(expectedOutgoingRequest.bidderRequests[0].bidderCode);
expect(auctionEndRequest.bidderRequests[0].bids).to.have.length(1);
expect(typeof auctionEndRequest.bidderRequests[0].bids[0].bidder).to.equal('undefined');
- expect(auctionEndRequest.bidderRequests[0].bids[0].adUnitCode).to.equal(requestOutgoing.bidderRequests[0].bids[0].adUnitCode);
+ expect(auctionEndRequest.bidderRequests[0].bids[0].adUnitCode).to.equal(expectedOutgoingRequest.bidderRequests[0].bids[0].adUnitCode);
expect(typeof auctionEndRequest.bidderRequests[0].bids[0].params).to.equal('undefined');
expect(typeof auctionEndRequest.bidderRequests[0].bids[0].src).to.equal('undefined');
- expect(auctionEndRequest.bidderRequests[0].refererInfo.topmostLocation).to.equal(requestOutgoing.bidderRequests[0].refererInfo.topmostLocation);
+ expect(auctionEndRequest.bidderRequests[0].refererInfo.topmostLocation).to.equal(expectedOutgoingRequest.bidderRequests[0].refererInfo.topmostLocation);
expect(auctionEndRequest.bidsReceived).to.have.length(1);
- expect(auctionEndRequest.bidsReceived[0].bidderCode).to.equal(requestOutgoing.bidsReceived[0].bidderCode);
- expect(auctionEndRequest.bidsReceived[0].width).to.equal(requestOutgoing.bidsReceived[0].width);
- expect(auctionEndRequest.bidsReceived[0].height).to.equal(requestOutgoing.bidsReceived[0].height);
- expect(auctionEndRequest.bidsReceived[0].mediaType).to.equal(requestOutgoing.bidsReceived[0].mediaType);
- expect(auctionEndRequest.bidsReceived[0].cpm).to.equal(requestOutgoing.bidsReceived[0].cpm);
- expect(auctionEndRequest.bidsReceived[0].adUnitCode).to.equal(requestOutgoing.bidsReceived[0].adUnitCode);
+ expect(auctionEndRequest.bidsReceived[0].bidderCode).to.equal(expectedOutgoingRequest.bidsReceived[0].bidderCode);
+ expect(auctionEndRequest.bidsReceived[0].width).to.equal(expectedOutgoingRequest.bidsReceived[0].width);
+ expect(auctionEndRequest.bidsReceived[0].height).to.equal(expectedOutgoingRequest.bidsReceived[0].height);
+ expect(auctionEndRequest.bidsReceived[0].mediaType).to.equal(expectedOutgoingRequest.bidsReceived[0].mediaType);
+ expect(auctionEndRequest.bidsReceived[0].cpm).to.equal(expectedOutgoingRequest.bidsReceived[0].cpm);
+ expect(auctionEndRequest.bidsReceived[0].currency).to.equal(expectedOutgoingRequest.bidsReceived[0].currency);
+ expect(auctionEndRequest.bidsReceived[0].originalCpm).to.equal(expectedOutgoingRequest.bidsReceived[0].originalCpm);
+ expect(auctionEndRequest.bidsReceived[0].originalCurrency).to.equal(expectedOutgoingRequest.bidsReceived[0].originalCurrency);
+ expect(auctionEndRequest.bidsReceived[0].adUnitCode).to.equal(expectedOutgoingRequest.bidsReceived[0].adUnitCode);
expect(typeof auctionEndRequest.bidsReceived[0].source).to.equal('undefined');
done();
diff --git a/test/spec/modules/omsBidAdapter_spec.js b/test/spec/modules/omsBidAdapter_spec.js
index a7b7ba09113..10a9c4c946c 100644
--- a/test/spec/modules/omsBidAdapter_spec.js
+++ b/test/spec/modules/omsBidAdapter_spec.js
@@ -247,6 +247,28 @@ describe('omsBidAdapter', function () {
expect(data.user.ext.ids).is.deep.equal(userId);
});
+ it('sends gpid parameters', function () {
+ bidRequests[0].ortb2Imp = {
+ 'ext': {
+ 'gpid': '/1111/home-left',
+ 'data': {
+ 'adserver': {
+ 'name': 'gam',
+ 'adslot': '/1111/home'
+ },
+ 'pbadslot': '/1111/home-left'
+ }
+ }
+ }
+
+ const data = JSON.parse(spec.buildRequests(bidRequests).data);
+ expect(data.imp[0].ext).to.not.be.undefined;
+ expect(data.imp[0].ext.gpid).to.not.be.undefined;
+ expect(data.imp[0].ext.adserverName).to.not.be.undefined;
+ expect(data.imp[0].ext.adslot).to.not.be.undefined;
+ expect(data.imp[0].ext.pbadslot).to.not.be.undefined;
+ });
+
context('when element is fully in view', function () {
it('returns 100', function () {
Object.assign(element, {width: 600, height: 400});
diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js
index c3d8a4ee0e1..93db5ffc57f 100644
--- a/test/spec/modules/onetagBidAdapter_spec.js
+++ b/test/spec/modules/onetagBidAdapter_spec.js
@@ -273,6 +273,7 @@ describe('onetag', function () {
});
it('should send GDPR consent data', function () {
let consentString = 'consentString';
+ let addtlConsent = '2~1.35.41.101~dv.9.21.81';
let bidderRequest = {
'bidderCode': 'onetag',
'auctionId': '1d1a030790a475',
@@ -280,7 +281,8 @@ describe('onetag', function () {
'timeout': 3000,
'gdprConsent': {
consentString: consentString,
- gdprApplies: true
+ gdprApplies: true,
+ addtlConsent: addtlConsent
}
};
let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
@@ -289,6 +291,7 @@ describe('onetag', function () {
expect(payload).to.exist;
expect(payload.gdprConsent).to.exist;
expect(payload.gdprConsent.consentString).to.exist.and.to.equal(consentString);
+ expect(payload.gdprConsent.addtlConsent).to.exist.and.to.equal(addtlConsent);
expect(payload.gdprConsent.consentRequired).to.exist.and.to.be.true;
});
it('Should send GPP consent data', function () {
diff --git a/test/spec/modules/opscoBidAdapter_spec.js b/test/spec/modules/opscoBidAdapter_spec.js
new file mode 100644
index 00000000000..38cacff8f82
--- /dev/null
+++ b/test/spec/modules/opscoBidAdapter_spec.js
@@ -0,0 +1,260 @@
+import {expect} from 'chai';
+import {spec} from 'modules/opscoBidAdapter';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+
+describe('opscoBidAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', () => {
+ it('exists and is a function', () => {
+ expect(adapter.callBids).to.exist.and.to.be.a('function')
+ })
+ })
+
+ describe('isBidRequestValid', function () {
+ const validBid = {
+ bidder: 'opsco',
+ params: {
+ placementId: '123',
+ publisherId: '456'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ }
+ };
+
+ it('should return true when required params are present', function () {
+ expect(spec.isBidRequestValid(validBid)).to.be.true;
+ });
+
+ it('should return false when placementId is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.params.placementId;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when publisherId is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.params.publisherId;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when mediaTypes.banner.sizes is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.mediaTypes.banner.sizes;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when mediaTypes.banner is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.mediaTypes.banner;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when bid params are missing', function () {
+ const invalidBid = {bidder: 'opsco'};
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when bid params are empty', function () {
+ const invalidBid = {bidder: 'opsco', params: {}};
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let validBid, bidderRequest;
+
+ beforeEach(function () {
+ validBid = {
+ bidder: 'opsco',
+ params: {
+ placementId: '123',
+ publisherId: '456'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ }
+ };
+
+ bidderRequest = {
+ bidderRequestId: 'bid123',
+ refererInfo: {
+ domain: 'example.com',
+ page: 'https://example.com/page',
+ ref: 'https://referrer.com'
+ },
+ gdprConsent: {
+ consentString: 'GDPR_CONSENT_STRING',
+ gdprApplies: true
+ },
+ };
+ });
+
+ it('should return true when banner sizes are defined', function () {
+ expect(spec.isBidRequestValid(validBid)).to.be.true;
+ });
+
+ it('should return false when banner sizes are invalid', function () {
+ const invalidSizes = [
+ '2:1',
+ undefined,
+ 123,
+ 'undefined'
+ ];
+
+ invalidSizes.forEach((sizes) => {
+ validBid.mediaTypes.banner.sizes = sizes;
+ expect(spec.isBidRequestValid(validBid)).to.be.false;
+ });
+ });
+
+ it('should send GDPR consent in the payload if present', function () {
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).user.ext.consent).to.deep.equal('GDPR_CONSENT_STRING');
+ });
+
+ it('should send CCPA in the payload if present', function () {
+ const ccpa = '1YYY';
+ bidderRequest.uspConsent = ccpa;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).regs.ext.us_privacy).to.equal(ccpa);
+ });
+
+ it('should send eids in the payload if present', function () {
+ const eids = {data: [{source: 'test', uids: [{id: '123', ext: {}}]}]};
+ validBid.userIdAsEids = eids;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).user.ext.eids).to.deep.equal(eids);
+ });
+
+ it('should send schain in the payload if present', function () {
+ const schain = {'ver': '1.0', 'complete': 1, 'nodes': [{'asi': 'exchange1.com', 'sid': '1234', 'hp': 1}]};
+ validBid.schain = schain;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).source.ext.schain).to.deep.equal(schain);
+ });
+
+ it('should correctly identify test mode', function () {
+ validBid.params.test = true;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).test).to.equal(1);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const validResponse = {
+ body: {
+ seatbid: [
+ {
+ bid: [
+ {
+ impid: 'bid1',
+ price: 1.5,
+ w: 300,
+ h: 250,
+ crid: 'creative1',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ adm: 'Ad content
',
+ mtype: 1
+ },
+ {
+ impid: 'bid2',
+ price: 2.0,
+ w: 728,
+ h: 90,
+ crid: 'creative2',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ adm: 'Ad content
',
+ mtype: 1
+ }
+ ]
+ }
+ ]
+ }
+ };
+
+ const emptyResponse = {
+ body: {
+ seatbid: []
+ }
+ };
+
+ it('should return an array of bid objects with valid response', function () {
+ const interpretedBids = spec.interpretResponse(validResponse);
+ const expectedBids = validResponse.body.seatbid[0].bid;
+ expect(interpretedBids).to.have.lengthOf(expectedBids.length);
+ expectedBids.forEach((expectedBid, index) => {
+ expect(interpretedBids[index]).to.have.property('requestId', expectedBid.impid);
+ expect(interpretedBids[index]).to.have.property('cpm', expectedBid.price);
+ expect(interpretedBids[index]).to.have.property('width', expectedBid.w);
+ expect(interpretedBids[index]).to.have.property('height', expectedBid.h);
+ expect(interpretedBids[index]).to.have.property('creativeId', expectedBid.crid);
+ expect(interpretedBids[index]).to.have.property('currency', expectedBid.currency);
+ expect(interpretedBids[index]).to.have.property('netRevenue', expectedBid.netRevenue);
+ expect(interpretedBids[index]).to.have.property('ttl', expectedBid.ttl);
+ expect(interpretedBids[index]).to.have.property('ad', expectedBid.adm);
+ expect(interpretedBids[index]).to.have.property('mediaType', expectedBid.mtype);
+ });
+ });
+
+ it('should return an empty array with empty response', function () {
+ const interpretedBids = spec.interpretResponse(emptyResponse);
+ expect(interpretedBids).to.be.an('array').that.is.empty;
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ const RESPONSE = {
+ body: {
+ ext: {
+ usersync: {
+ sovrn: {
+ syncs: [{type: 'iframe', url: 'https://sovrn.com/iframe_sync'}]
+ },
+ appnexus: {
+ syncs: [{type: 'image', url: 'https://appnexus.com/image_sync'}]
+ }
+ }
+ }
+ }
+ };
+
+ it('should return empty array if no options are provided', function () {
+ const opts = spec.getUserSyncs({});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return empty array if neither iframe nor pixel is enabled', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return syncs only for iframe sync type', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [RESPONSE]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('iframe');
+ expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync.sovrn.syncs[0].url);
+ });
+
+ it('should return syncs only for pixel sync types', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [RESPONSE]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync.appnexus.syncs[0].url);
+ });
+
+ it('should return syncs when both iframe and pixel are enabled', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [RESPONSE]);
+ expect(opts.length).to.equal(2);
+ });
+ });
+});
diff --git a/test/spec/modules/pangleBidAdapter_spec.js b/test/spec/modules/pangleBidAdapter_spec.js
index 6d8f9a66bcf..f2504a810c4 100644
--- a/test/spec/modules/pangleBidAdapter_spec.js
+++ b/test/spec/modules/pangleBidAdapter_spec.js
@@ -127,11 +127,15 @@ describe('pangle bid adapter', function () {
describe('buildRequests', function () {
it('creates request data', function () {
- let request = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[0];
- expect(request).to.exist.and.to.be.a('object');
- const payload = request.data;
- expect(payload.imp[0]).to.have.property('id', REQUEST[0].bidId);
- expect(payload.imp[1]).to.have.property('id', REQUEST[1].bidId);
+ let request1 = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[0];
+ expect(request1).to.exist.and.to.be.a('object');
+ const payload1 = request1.data;
+ expect(payload1.imp[0]).to.have.property('id', REQUEST[0].bidId);
+
+ let request2 = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[1];
+ expect(request2).to.exist.and.to.be.a('object');
+ const payload2 = request2.data;
+ expect(payload2.imp[0]).to.have.property('id', REQUEST[1].bidId);
});
});
diff --git a/test/spec/modules/pstudioBidAdapter_spec.js b/test/spec/modules/pstudioBidAdapter_spec.js
new file mode 100644
index 00000000000..52ecb820ed3
--- /dev/null
+++ b/test/spec/modules/pstudioBidAdapter_spec.js
@@ -0,0 +1,514 @@
+import { assert } from 'chai';
+import sinon from 'sinon';
+import { spec, storage } from 'modules/pstudioBidAdapter.js';
+import { deepClone } from '../../../src/utils.js';
+
+describe('PStudioAdapter', function () {
+ let sandbox;
+
+ beforeEach(function () {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
+ const bannerBid = {
+ bidder: 'pstudio',
+ params: {
+ pubid: '258c2a8d-d2ad-4c31-a2a5-e63001186456',
+ floorPrice: 1.15,
+ },
+ adUnitCode: 'test-div-1',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 600],
+ ],
+ pos: 0,
+ name: 'some-name',
+ },
+ },
+ bidId: '30b31c1838de1e',
+ };
+
+ const videoBid = {
+ bidder: 'pstudio',
+ params: {
+ pubid: '258c2a8d-d2ad-4c31-a2a5-e63001186456',
+ floorPrice: 1.15,
+ },
+ adUnitCode: 'test-div-1',
+ mediaTypes: {
+ video: {
+ playerSize: [[300, 250]],
+ mimes: ['video/mp4'],
+ minduration: 5,
+ maxduration: 30,
+ protocols: [2, 3],
+ startdelay: 5,
+ placement: 2,
+ skip: 1,
+ skipafter: 1,
+ minbitrate: 10,
+ maxbitrate: 10,
+ delivery: 1,
+ playbackmethod: [1, 3],
+ api: [2],
+ linearity: 1,
+ },
+ },
+ bidId: '30b31c1838de1e',
+ };
+
+ const bidWithOptionalParams = deepClone(bannerBid);
+ bidWithOptionalParams.params['bcat'] = ['IAB17-18', 'IAB7-42'];
+ bidWithOptionalParams.params['badv'] = ['ford.com'];
+ bidWithOptionalParams.params['bapp'] = ['com.foo.mygame'];
+ bidWithOptionalParams.params['regs'] = {
+ coppa: 1,
+ };
+
+ bidWithOptionalParams.userId = {
+ uid2: {
+ id: '7505e78e-4a9b-4011-8901-0e00c3f55ea9',
+ },
+ };
+
+ const emptyOrtb2BidderRequest = { ortb2: {} };
+
+ const baseBidderRequest = {
+ ortb2: {
+ device: {
+ w: 1680,
+ h: 342,
+ },
+ },
+ };
+
+ const extendedBidderRequest = deepClone(baseBidderRequest);
+ extendedBidderRequest.ortb2['device'] = {
+ dnt: 0,
+ ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
+ lmt: 0,
+ ip: '192.0.0.1',
+ ipv6: '2001:0000:130F:0000:0000:09C0:876A:130B',
+ devicetype: 2,
+ make: 'some_producer',
+ model: 'some_model',
+ os: 'some_os',
+ osv: 'some_version',
+ js: 1,
+ language: 'en',
+ carrier: 'WiFi',
+ connectiontype: 0,
+ ifa: 'some_ifa',
+ geo: {
+ lat: 50.4,
+ lon: 40.2,
+ country: 'some_country_code',
+ region: 'some_region_code',
+ regionfips104: 'some_fips_code',
+ metro: 'metro_code',
+ city: 'city_code',
+ zip: 'zip_code',
+ type: 2,
+ },
+ ext: {
+ ifatype: 'dpid',
+ },
+ };
+ extendedBidderRequest.ortb2['site'] = {
+ id: 'some_id',
+ name: 'example',
+ domain: 'page.example.com',
+ cat: ['IAB2'],
+ sectioncat: ['IAB2-2'],
+ pagecat: ['IAB2-2'],
+ page: 'https://page.example.com/here.html',
+ ref: 'https://ref.example.com',
+ publisher: {
+ name: 'some_name',
+ cat: ['IAB2'],
+ domain: 'https://page.example.com/here.html',
+ },
+ content: {
+ id: 'some_id',
+ episode: 22,
+ title: 'New episode.',
+ series: 'New series.',
+ artist: 'New artist',
+ genre: 'some genre',
+ album: 'New album',
+ isrc: 'AA-6Q7-20-00047',
+ season: 'New season',
+ },
+ mobile: 0,
+ };
+ extendedBidderRequest.ortb2['app'] = {
+ id: 'some_id',
+ name: 'example',
+ bundle: 'some_bundle',
+ domain: 'page.example.com',
+ storeurl: 'https://store.example.com',
+ cat: ['IAB2'],
+ sectioncat: ['IAB2-2'],
+ pagecat: ['IAB2-2'],
+ ver: 'some_version',
+ privacypolicy: 0,
+ paid: 0,
+ keywords: 'some, example, keywords',
+ publisher: {
+ name: 'some_name',
+ cat: ['IAB2'],
+ domain: 'https://page.example.com/here.html',
+ },
+ content: {
+ id: 'some_id',
+ episode: 22,
+ title: 'New episode.',
+ series: 'New series.',
+ artist: 'New artist',
+ genre: 'some genre',
+ album: 'New album',
+ isrc: 'AA-6Q7-20-00047',
+ season: 'New season',
+ },
+ };
+ extendedBidderRequest.ortb2['user'] = {
+ yob: 1992,
+ gender: 'M',
+ };
+ extendedBidderRequest.ortb2['regs'] = {
+ coppa: 0,
+ };
+
+ describe('isBidRequestValid', function () {
+ it('should return true when publisher id found', function () {
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
+ });
+
+ it('should return true for video bid', () => {
+ expect(spec.isBidRequestValid(videoBid)).to.equal(true);
+ });
+
+ it('should return false when publisher id not found', function () {
+ const localBid = deepClone(bannerBid);
+ delete localBid.params.pubid;
+ delete localBid.params.floorPrice;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when playerSize in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.playerSize;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when mimes in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.mimes;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when protocols in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.protocols;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bannerRequest = spec.buildRequests([bannerBid], baseBidderRequest);
+ const bannerPayload = JSON.parse(bannerRequest[0].data);
+ const videoRequest = spec.buildRequests([videoBid], baseBidderRequest);
+ const videoPayload = JSON.parse(videoRequest[0].data);
+
+ it('should properly map ids in request payload', function () {
+ expect(bannerPayload.id).to.equal(bannerBid.bidId);
+ expect(bannerPayload.adtagid).to.equal(bannerBid.adUnitCode);
+ });
+
+ it('should properly map banner mediaType in request payload', function () {
+ expect(bannerPayload.banner_properties).to.deep.equal({
+ name: bannerBid.mediaTypes.banner.name,
+ sizes: bannerBid.mediaTypes.banner.sizes,
+ pos: bannerBid.mediaTypes.banner.pos,
+ });
+ });
+
+ it('should properly map video mediaType in request payload', () => {
+ expect(videoPayload.video_properties).to.deep.equal({
+ w: videoBid.mediaTypes.video.playerSize[0][0],
+ h: videoBid.mediaTypes.video.playerSize[0][1],
+ mimes: videoBid.mediaTypes.video.mimes,
+ minduration: videoBid.mediaTypes.video.minduration,
+ maxduration: videoBid.mediaTypes.video.maxduration,
+ protocols: videoBid.mediaTypes.video.protocols,
+ startdelay: videoBid.mediaTypes.video.startdelay,
+ placement: videoBid.mediaTypes.video.placement,
+ skip: videoBid.mediaTypes.video.skip,
+ skipafter: videoBid.mediaTypes.video.skipafter,
+ minbitrate: videoBid.mediaTypes.video.minbitrate,
+ maxbitrate: videoBid.mediaTypes.video.maxbitrate,
+ delivery: videoBid.mediaTypes.video.delivery,
+ playbackmethod: videoBid.mediaTypes.video.playbackmethod,
+ api: videoBid.mediaTypes.video.api,
+ linearity: videoBid.mediaTypes.video.linearity,
+ });
+ });
+
+ it('should properly set required bidder params in request payload', function () {
+ expect(bannerPayload.pubid).to.equal(bannerBid.params.pubid);
+ expect(bannerPayload.floor_price).to.equal(bannerBid.params.floorPrice);
+ });
+
+ it('should omit optional bidder params or first-party data from bid request if they are not provided', function () {
+ assert.isUndefined(bannerPayload.bcat);
+ assert.isUndefined(bannerPayload.badv);
+ assert.isUndefined(bannerPayload.bapp);
+ assert.isUndefined(bannerPayload.user);
+ assert.isUndefined(bannerPayload.device);
+ assert.isUndefined(bannerPayload.site);
+ assert.isUndefined(bannerPayload.app);
+ assert.isUndefined(bannerPayload.user_ids);
+ assert.isUndefined(bannerPayload.regs);
+ });
+
+ it('should properly set optional bidder parameters', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ baseBidderRequest
+ );
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.bcat).to.deep.equal(['IAB17-18', 'IAB7-42']);
+ expect(payload.badv).to.deep.equal(['ford.com']);
+ expect(payload.bapp).to.deep.equal(['com.foo.mygame']);
+ });
+
+ it('should properly set optional user_ids', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ baseBidderRequest
+ );
+ const {
+ user: { uid2_token },
+ } = JSON.parse(request[0].data);
+ const expectedUID = '7505e78e-4a9b-4011-8901-0e00c3f55ea9';
+
+ expect(uid2_token).to.equal(expectedUID);
+ });
+
+ it('should properly set optional user_ids when no first party data is provided', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ emptyOrtb2BidderRequest
+ );
+ const {
+ user: { uid2_token },
+ } = JSON.parse(request[0].data);
+ const expectedUID = '7505e78e-4a9b-4011-8901-0e00c3f55ea9';
+
+ expect(uid2_token).to.equal(expectedUID);
+ });
+
+ it('should properly handle first-party data', function () {
+ const request = spec.buildRequests([bannerBid], extendedBidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.user).to.deep.equal(extendedBidderRequest.ortb2.user);
+ expect(payload.device).to.deep.equal(extendedBidderRequest.ortb2.device);
+ expect(payload.site).to.deep.equal(extendedBidderRequest.ortb2.site);
+ expect(payload.app).to.deep.equal(extendedBidderRequest.ortb2.app);
+ expect(payload.regs).to.deep.equal(extendedBidderRequest.ortb2.regs);
+ });
+
+ it('should not set first-party data if nothing is provided in ORTB2 param', function () {
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload).not.to.haveOwnProperty('user');
+ expect(payload).not.to.haveOwnProperty('device');
+ expect(payload).not.to.haveOwnProperty('site');
+ expect(payload).not.to.haveOwnProperty('app');
+ expect(payload).not.to.haveOwnProperty('regs');
+ });
+
+ it('should set user id if proper cookie is present', function () {
+ const cookie = '157bc918-b961-4216-ac72-29fc6363edcb';
+ sandbox.stub(storage, 'getCookie').returns(cookie);
+
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.user.id).to.equal(cookie);
+ });
+
+ it('should not set user id if proper cookie not present', function () {
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload).not.to.haveOwnProperty('user');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const serverResponse = {
+ body: {
+ id: '123141241231',
+ bids: [
+ {
+ cpm: 1.02,
+ width: 300,
+ height: 600,
+ currency: 'USD',
+ ad: 'Hello ad
',
+ creative_id: 'crid12345',
+ net_revenue: true,
+ meta: {
+ advertiser_domains: ['https://advertiser.com'],
+ },
+ },
+ ],
+ },
+ };
+
+ const serverVideoResponse = {
+ body: {
+ id: '123141241231',
+ bids: [
+ {
+ vast_url: 'https://v.a/st.xml',
+ cpm: 5,
+ width: 640,
+ height: 480,
+ currency: 'USD',
+ creative_id: 'crid12345',
+ net_revenue: true,
+ meta: {
+ advertiser_domains: ['https://advertiser.com'],
+ },
+ },
+ ],
+ },
+ };
+
+ const bidRequest = {
+ method: 'POST',
+ url: 'test-url',
+ data: JSON.stringify({
+ id: '12345',
+ pubid: 'somepubid',
+ }),
+ };
+
+ it('should properly parse response from server', function () {
+ const expectedResponse = {
+ requestId: JSON.parse(bidRequest.data).id,
+ cpm: serverResponse.body.bids[0].cpm,
+ width: serverResponse.body.bids[0].width,
+ height: serverResponse.body.bids[0].height,
+ ad: serverResponse.body.bids[0].ad,
+ currency: serverResponse.body.bids[0].currency,
+ creativeId: serverResponse.body.bids[0].creative_id,
+ netRevenue: serverResponse.body.bids[0].net_revenue,
+ meta: {
+ advertiserDomains:
+ serverResponse.body.bids[0].meta.advertiser_domains,
+ },
+ ttl: 300,
+ };
+ const parsedResponse = spec.interpretResponse(serverResponse, bidRequest);
+
+ expect(parsedResponse[0]).to.deep.equal(expectedResponse);
+ });
+
+ it('should properly parse video response from server', function () {
+ const expectedResponse = {
+ requestId: JSON.parse(bidRequest.data).id,
+ cpm: serverVideoResponse.body.bids[0].cpm,
+ width: serverVideoResponse.body.bids[0].width,
+ height: serverVideoResponse.body.bids[0].height,
+ currency: serverVideoResponse.body.bids[0].currency,
+ creativeId: serverVideoResponse.body.bids[0].creative_id,
+ netRevenue: serverVideoResponse.body.bids[0].net_revenue,
+ mediaType: 'video',
+ vastUrl: serverVideoResponse.body.bids[0].vast_url,
+ vastXml: undefined,
+ meta: {
+ advertiserDomains:
+ serverVideoResponse.body.bids[0].meta.advertiser_domains,
+ },
+ ttl: 300,
+ };
+ const parsedResponse = spec.interpretResponse(
+ serverVideoResponse,
+ bidRequest
+ );
+
+ expect(parsedResponse[0]).to.deep.equal(expectedResponse);
+ });
+
+ it('should return empty array if no bids are returned', function () {
+ const emptyResponse = deepClone(serverResponse);
+ emptyResponse.body.bids = undefined;
+
+ const parsedResponse = spec.interpretResponse(emptyResponse, bidRequest);
+
+ expect(parsedResponse).to.deep.equal([]);
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ it('should return sync object with correctly injected user id', function () {
+ sandbox.stub(storage, 'getCookie').returns('testid');
+
+ const result = spec.getUserSyncs({}, {}, {}, {});
+
+ expect(result).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=k1on5ig&ttd_tpi=1&ttd_puid=testid&dsp=ttd',
+ },
+ {
+ type: 'image',
+ url: 'https://dsp.myads.telkomsel.com/api/v1/pixel?uid=testid',
+ },
+ ]);
+ });
+
+ it('should generate user id and put the same uuid it into sync object', function () {
+ sandbox.stub(storage, 'getCookie').returns(undefined);
+
+ const result = spec.getUserSyncs({}, {}, {}, {});
+ const url1 = result[0].url;
+ const url2 = result[1].url;
+
+ const expectedUID1 = extractValueFromURL(url1, 'ttd_puid');
+ const expectedUID2 = extractValueFromURL(url2, 'uid');
+
+ expect(expectedUID1).to.equal(expectedUID2);
+
+ expect(result[0]).deep.equal({
+ type: 'image',
+ url: `https://match.adsrvr.org/track/cmf/generic?ttd_pid=k1on5ig&ttd_tpi=1&ttd_puid=${expectedUID1}&dsp=ttd`,
+ });
+ expect(result[1]).deep.equal({
+ type: 'image',
+ url: `https://dsp.myads.telkomsel.com/api/v1/pixel?uid=${expectedUID2}`,
+ });
+ // Helper function to extract UUID from URL
+ function extractValueFromURL(url, key) {
+ const match = url.match(new RegExp(`[?&]${key}=([^&]*)`));
+ return match ? match[1] : null;
+ }
+ });
+ });
+});
diff --git a/test/spec/modules/publirBidAdapter_spec.js b/test/spec/modules/publirBidAdapter_spec.js
new file mode 100644
index 00000000000..60840b82efb
--- /dev/null
+++ b/test/spec/modules/publirBidAdapter_spec.js
@@ -0,0 +1,488 @@
+import { expect } from 'chai';
+import { spec } from 'modules/publirBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import { config } from 'src/config.js';
+import { BANNER } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
+
+const ENDPOINT = 'https://prebid.publir.com/publirPrebidEndPoint';
+const RTB_DOMAIN_TEST = 'prebid.publir.com';
+const TTL = 360;
+
+describe('publirAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('bid adapter', function () {
+ it('should have aliases', function () {
+ expect(spec.aliases).to.be.an('array').that.is.not.empty;
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when pubId is missing', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {}
+ };
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'pubId': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '""'
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'publir',
+ }
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('sends bid request to rtbDomain ENDPOINT via POST', function () {
+ bidRequests[0].params.rtbDomain = RTB_DOMAIN_TEST;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
+ });
+
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
+
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
+ });
+
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
+
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
+ });
+
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
+
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
+
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
+
+ it('should check sua param in bid request', function() {
+ const sua = {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': ['12', '4', '0']
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': [ '12', '4', '0' ]
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [
+ {
+ cpm: 12.5,
+ ad: '""',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER,
+ campId: '65902db45721d690ee0bc8c3'
+ }]
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: TTL,
+ creativeId: '639153ddd0s443',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ ad_key: '9b5e00f2-8831-4efa-a933-c4f68710ffc0'
+ },
+ ad: '""',
+ campId: '65902db45721d690ee0bc8c3',
+ bidder: 'publir'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
+
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
+ });
+ })
+
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ })
+ })
+});
diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
index c6447905ecd..951b5135260 100755
--- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
+++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
@@ -100,7 +100,7 @@ const BID2 = Object.assign({}, BID, {
adserverTargeting: {
'hb_bidder': 'pubmatic',
'hb_adid': '3bd4ebb1c900e2',
- 'hb_pb': '1.500',
+ 'hb_pb': 1.50,
'hb_size': '728x90',
'hb_source': 'server'
},
@@ -606,6 +606,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
@@ -640,6 +641,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
@@ -812,6 +814,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -1035,6 +1038,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
});
it('Logger: currency conversion check', function() {
@@ -1149,6 +1153,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
expect(data.dvc).to.deep.equal({'plt': 2});
// respective tracker slot
let firstTracker = requests[1].url;
@@ -1209,6 +1214,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.dvc).to.deep.equal({'plt': 1});
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// respective tracker slot
let firstTracker = requests[1].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -1267,6 +1273,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// respective tracker slot
let firstTracker = requests[1].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -1388,6 +1395,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
});
it('Logger: best case + win tracker in case of Bidder Aliases', function() {
@@ -1466,6 +1474,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
@@ -1501,6 +1510,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
@@ -1596,6 +1606,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js
index 5d59ff99a89..fda2c853e87 100644
--- a/test/spec/modules/pubmaticBidAdapter_spec.js
+++ b/test/spec/modules/pubmaticBidAdapter_spec.js
@@ -1781,6 +1781,37 @@ describe('PubMatic adapter', function () {
expect(data2.regs).to.equal(undefined);// USP/CCPAs
});
+ it('Request params should include DSA signals if present', function () {
+ const dsa = {
+ dsarequired: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [
+ {
+ domain: 'platform1domain.com',
+ dsaparams: [1]
+ },
+ {
+ domain: 'SSP2domain.com',
+ dsaparams: [1, 2]
+ }
+ ]
+ };
+
+ let bidRequest = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa
+ }
+ }
+ }
+ };
+ let request = spec.buildRequests(bidRequests, bidRequest);
+ let data = JSON.parse(request.data);
+ assert.deepEqual(data.regs.ext.dsa, dsa);
+ });
+
it('Request params check with JW player params', function() {
let bidRequests = [
{
@@ -3753,6 +3784,16 @@ describe('PubMatic adapter', function () {
describe('Preapare metadata', function () {
it('Should copy all fields from ext to meta', function () {
+ const dsa = {
+ behalf: 'Advertiser',
+ paid: 'Advertiser',
+ transparency: [{
+ domain: 'dsp1domain.com',
+ dsaparams: [1, 2]
+ }],
+ adrender: 1
+ };
+
const bid = {
'adomain': [
'mystartab.com'
@@ -3764,6 +3805,7 @@ describe('PubMatic adapter', function () {
'deal_channel': 1,
'bidtype': 0,
advertiserId: 'adid',
+ dsa,
// networkName: 'nwnm',
// primaryCatId: 'pcid',
// advertiserName: 'adnm',
@@ -3795,6 +3837,7 @@ describe('PubMatic adapter', function () {
expect(br.meta.secondaryCatIds[0]).to.equal('IAB_CATEGORY');
expect(br.meta.advertiserDomains).to.be.an('array').with.length.above(0); // adomain
expect(br.meta.clickUrl).to.equal('mystartab.com'); // adomain
+ expect(br.meta.dsa).to.equal(dsa); // dsa
});
it('Should be empty, when ext and adomain is absent in bid object', function () {
diff --git a/test/spec/modules/rasBidAdapter_spec.js b/test/spec/modules/rasBidAdapter_spec.js
index 719e15ad695..f172d192221 100644
--- a/test/spec/modules/rasBidAdapter_spec.js
+++ b/test/spec/modules/rasBidAdapter_spec.js
@@ -1,7 +1,6 @@
import { expect } from 'chai';
import { spec } from 'modules/rasBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
-import {getAdUnitSizes} from '../../../src/utils';
const CSR_ENDPOINT = 'https://csr.onet.pl/4178463/csr-006/csr.json?nid=4178463&';
@@ -64,6 +63,20 @@ describe('rasBidAdapter', function () {
customParams: {
test: 'name=value'
}
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ }
}
};
const bid2 = {
@@ -75,6 +88,16 @@ describe('rasBidAdapter', function () {
area: 'areatest',
site: 'test',
network: '4178463'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 750,
+ 300
+ ]
+ ]
+ }
}
};
@@ -128,6 +151,7 @@ describe('rasBidAdapter', function () {
}
};
const requests = spec.buildRequests([bidCopy, bid2]);
+
expect(requests[0].url).to.have.string(CSR_ENDPOINT);
expect(requests[0].url).to.have.string('slot0=test');
expect(requests[0].url).to.have.string('id0=1');
@@ -148,6 +172,39 @@ describe('rasBidAdapter', function () {
expect(requests[0].url).to.have.string('kvadunit=test%2Fareatest');
expect(requests[0].url).to.have.string('pos0=0');
});
+
+ it('should parse dsainfo when available', function () {
+ const bidCopy = { ...bid };
+ bidCopy.params = {
+ ...bid.params,
+ pageContext: {
+ dv: 'test/areatest',
+ du: 'https://example.com/',
+ dr: 'https://example.org/',
+ keyWords: ['val1', 'val2'],
+ keyValues: {
+ adunit: 'test/areatest'
+ }
+ }
+ };
+ let bidderRequest = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ required: 1
+ }
+ }
+ }
+ }
+ };
+ let requests = spec.buildRequests([bidCopy], bidderRequest);
+ expect(requests[0].url).to.have.string('dsainfo=1');
+
+ bidderRequest.ortb2.regs.ext.dsa.required = 0;
+ requests = spec.buildRequests([bidCopy], bidderRequest);
+ expect(requests[0].url).to.have.string('dsainfo=0');
+ });
});
describe('interpretResponse', function () {
@@ -172,7 +229,7 @@ describe('rasBidAdapter', function () {
it('should get correct bid response', function () {
const resp = spec.interpretResponse({ body: response }, { bidIds: [{ slot: 'flat-belkagorna', bidId: 1 }] });
- expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'ad', 'meta');
+ expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'ad', 'meta', 'actgMatch', 'mediaType');
expect(resp.length).to.equal(1);
});
@@ -245,4 +302,309 @@ describe('rasBidAdapter', function () {
expect(resp).to.deep.equal({bids: [], fledgeAuctionConfigs: auctionConfigs});
});
});
+
+ describe('buildNativeRequests', function () {
+ const bid = {
+ sizes: 'fluid',
+ bidder: 'ras',
+ bidId: 1,
+ params: {
+ slot: 'nativestd',
+ area: 'areatest',
+ site: 'test',
+ slotSequence: '0',
+ network: '4178463',
+ customParams: {
+ test: 'name=value'
+ }
+ },
+ mediaTypes: {
+ native: {
+ clickUrl: {
+ required: true
+ },
+ image: {
+ required: true
+ },
+ sponsoredBy: {
+ len: 25,
+ required: true
+ },
+ title: {
+ len: 50,
+ required: true
+ }
+ }
+ }
+ };
+
+ it('should parse bids to native request', function () {
+ const requests = spec.buildRequests([bid], {
+ 'gdprConsent': {
+ 'gdprApplies': true,
+ 'consentString': 'some-consent-string'
+ },
+ 'refererInfo': {
+ 'ref': 'https://example.org/',
+ 'page': 'https://example.com/'
+ }
+ });
+
+ expect(requests[0].url).to.have.string(CSR_ENDPOINT);
+ expect(requests[0].url).to.have.string('slot0=nativestd');
+ expect(requests[0].url).to.have.string('id0=1');
+ expect(requests[0].url).to.have.string('site=test');
+ expect(requests[0].url).to.have.string('area=areatest');
+ expect(requests[0].url).to.have.string('cre_format=html');
+ expect(requests[0].url).to.have.string('systems=das');
+ expect(requests[0].url).to.have.string('ems_url=1');
+ expect(requests[0].url).to.have.string('bid_rate=1');
+ expect(requests[0].url).to.have.string('gdpr_applies=true');
+ expect(requests[0].url).to.have.string('euconsent=some-consent-string');
+ expect(requests[0].url).to.have.string('du=https%3A%2F%2Fexample.com%2F');
+ expect(requests[0].url).to.have.string('dr=https%3A%2F%2Fexample.org%2F');
+ expect(requests[0].url).to.have.string('test=name%3Dvalue');
+ expect(requests[0].url).to.have.string('cre_format0=native');
+ expect(requests[0].url).to.have.string('iusizes0=fluid');
+ });
+ });
+
+ describe('interpretNativeResponse', function () {
+ const response = {
+ 'adsCheck': 'ok',
+ 'geoloc': {},
+ 'ir': '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ 'iv': '202003191334467636346500',
+ 'ads': [
+ {
+ 'id': 'nativestd',
+ 'slot': 'nativestd',
+ 'prio': 10,
+ 'type': 'native',
+ 'bid_rate': 0.321123,
+ 'adid': 'das,50463,152276',
+ 'id_3': '12734'
+ }
+ ]
+ };
+ const responseTeaserStandard = {
+ adsCheck: 'ok',
+ geoloc: {},
+ ir: '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ iv: '202003191334467636346500',
+ ads: [
+ {
+ id: 'nativestd',
+ slot: 'nativestd',
+ prio: 10,
+ type: 'native',
+ bid_rate: 0.321123,
+ adid: 'das,50463,152276',
+ id_3: '12734',
+ data: {
+ fields: {
+ leadtext: 'BODY',
+ title: 'Headline',
+ image: '//img.url',
+ url: '//link.url',
+ impression: '//impression.url',
+ impression1: '//impression1.url',
+ impressionJs1: '//impressionJs1.url'
+ },
+ meta: {
+ slot: 'nativestd',
+ height: 1,
+ width: 1,
+ advertiser_name: 'Test Onet',
+ dsaurl: '//dsa.url',
+ adclick: '//adclick.url'
+ }
+ },
+ ems_link: '//ems.url'
+ }
+ ]
+ };
+ const responseNativeInFeed = {
+ adsCheck: 'ok',
+ geoloc: {},
+ ir: '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ iv: '202003191334467636346500',
+ ads: [
+ {
+ id: 'nativestd',
+ slot: 'nativestd',
+ prio: 10,
+ type: 'native',
+ bid_rate: 0.321123,
+ adid: 'das,50463,152276',
+ id_3: '12734',
+ data: {
+ fields: {
+ Body: 'BODY',
+ Calltoaction: 'Calltoaction',
+ Headline: 'Headline',
+ Image: '//img.url',
+ Sponsorlabel: 'nie',
+ Thirdpartyclicktracker: '//link.url',
+ imp: '//imp.url'
+ },
+ meta: {
+ slot: 'nativestd',
+ height: 1,
+ width: 1,
+ advertiser_name: 'Test Onet',
+ dsaurl: '//dsa.url',
+ adclick: '//adclick.url'
+ }
+ },
+ ems_link: '//ems.url'
+ }
+ ]
+ };
+ const expectedTeaserStandardOrtbResponse = {
+ ver: '1.2',
+ assets: [
+ {
+ id: 2,
+ img: {
+ url: '//img.url',
+ w: 1,
+ h: 1
+ }
+ },
+ {
+ id: 4,
+ title: {
+ text: 'Headline'
+ }
+ },
+ {
+ id: 3,
+ data: {
+ value: 'Test Onet',
+ type: 1
+ }
+ }
+ ],
+ link: {
+ url: '//adclick.url//link.url'
+ },
+ eventtrackers: [
+ {
+ event: 1,
+ method: 1,
+ url: '//ems.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//impression.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//impression1.url'
+ },
+ {
+ event: 1,
+ method: 2,
+ url: '//impressionJs1.url'
+ }
+ ],
+ privacy: '//dsa.url'
+ };
+ const expectedTeaserStandardResponse = {
+ sendTargetingKeys: false,
+ title: 'Headline',
+ image: {
+ url: '//img.url',
+ width: 1,
+ height: 1
+ },
+ clickUrl: '//adclick.url//link.url',
+ cta: '',
+ body: 'BODY',
+ sponsoredBy: 'Test Onet',
+ ortb: expectedTeaserStandardOrtbResponse,
+ privacyLink: '//dsa.url'
+ };
+ const expectedNativeInFeedOrtbResponse = {
+ ver: '1.2',
+ assets: [
+ {
+ id: 2,
+ img: {
+ url: '//img.url',
+ w: 1,
+ h: 1
+ }
+ },
+ {
+ id: 4,
+ title: {
+ text: 'Headline'
+ }
+ },
+ {
+ id: 3,
+ data: {
+ value: 'Test Onet',
+ type: 1
+ }
+ }
+ ],
+ link: {
+ url: '//adclick.url//link.url'
+ },
+ eventtrackers: [
+ {
+ event: 1,
+ method: 1,
+ url: '//ems.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//imp.url'
+ }
+ ],
+ privacy: '//dsa.url',
+ };
+ const expectedNativeInFeedResponse = {
+ sendTargetingKeys: false,
+ title: 'Headline',
+ image: {
+ url: '//img.url',
+ width: 1,
+ height: 1
+ },
+ clickUrl: '//adclick.url//link.url',
+ cta: 'Calltoaction',
+ body: 'BODY',
+ sponsoredBy: 'Test Onet',
+ ortb: expectedNativeInFeedOrtbResponse,
+ privacyLink: '//dsa.url'
+ };
+
+ it('should get correct bid native response', function () {
+ const resp = spec.interpretResponse({ body: response }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+
+ expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'meta', 'actgMatch', 'mediaType', 'native');
+ expect(resp.length).to.equal(1);
+ });
+
+ it('should get correct native response for TeaserStandard', function () {
+ const resp = spec.interpretResponse({ body: responseTeaserStandard }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+ const teaserStandardResponse = resp[0].native;
+
+ expect(JSON.stringify(teaserStandardResponse)).to.equal(JSON.stringify(expectedTeaserStandardResponse));
+ });
+
+ it('should get correct native response for NativeInFeed', function () {
+ const resp = spec.interpretResponse({ body: responseNativeInFeed }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+ const nativeInFeedResponse = resp[0].native;
+
+ expect(JSON.stringify(nativeInFeedResponse)).to.equal(JSON.stringify(expectedNativeInFeedResponse));
+ });
+ });
});
diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js
index 184bea07d04..55e8909f6c8 100644
--- a/test/spec/modules/rubiconBidAdapter_spec.js
+++ b/test/spec/modules/rubiconBidAdapter_spec.js
@@ -34,6 +34,7 @@ describe('the rubicon adapter', function () {
logErrorSpy;
/**
+ * @typedef {import('../../../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {Object} sizeMapConverted
* @property {string} sizeId
* @property {string} size
@@ -2267,17 +2268,6 @@ describe('the rubicon adapter', function () {
expect(payload.ext.prebid.analytics).to.be.undefined;
});
- it('should send video exp param correctly when set', function () {
- const bidderRequest = createVideoBidderRequest();
- config.setConfig({s2sConfig: {defaultTtl: 600}});
- let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest);
- let post = request.data;
-
- // should exp set to the right value according to config
- let imp = post.imp[0];
- expect(imp.exp).to.equal(600);
- });
-
it('should not send video exp at all if not set in s2sConfig config', function () {
const bidderRequest = createVideoBidderRequest();
let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest);
@@ -3086,7 +3076,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].width).to.equal(320);
expect(bids[0].height).to.equal(50);
expect(bids[0].cpm).to.equal(0.911);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].rubicon.advertiserId).to.equal(7);
expect(bids[0].rubicon.networkId).to.equal(8);
@@ -3103,7 +3093,7 @@ describe('the rubicon adapter', function () {
expect(bids[1].width).to.equal(300);
expect(bids[1].height).to.equal(250);
expect(bids[1].cpm).to.equal(0.811);
- expect(bids[1].ttl).to.equal(300);
+ expect(bids[1].ttl).to.equal(360);
expect(bids[1].netRevenue).to.equal(true);
expect(bids[1].rubicon.advertiserId).to.equal(7);
expect(bids[1].rubicon.networkId).to.equal(8);
@@ -3915,7 +3905,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].seatBidId).to.equal('0');
expect(bids[0].creativeId).to.equal('4259970');
expect(bids[0].cpm).to.equal(2);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].adserverTargeting).to.deep.equal({hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'});
expect(bids[0].mediaType).to.equal('video');
@@ -4007,7 +3997,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].seatBidId).to.equal('0');
expect(bids[0].creativeId).to.equal('4259970');
expect(bids[0].cpm).to.equal(2);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].adserverTargeting).to.deep.equal({hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'});
expect(bids[0].mediaType).to.equal('video');
diff --git a/test/spec/modules/setupadBidAdapter_spec.js b/test/spec/modules/setupadBidAdapter_spec.js
new file mode 100644
index 00000000000..d4ff73d005f
--- /dev/null
+++ b/test/spec/modules/setupadBidAdapter_spec.js
@@ -0,0 +1,348 @@
+import { spec } from 'modules/setupadBidAdapter.js';
+
+describe('SetupadAdapter', function () {
+ const userIdAsEids = [
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ atype: 1,
+ id: '01EAJWWNEPN3CYMM5N8M5VXY22',
+ },
+ ],
+ },
+ ];
+
+ const bidRequests = [
+ {
+ adUnitCode: 'test-div',
+ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
+ bidId: '22c4871113f461',
+ bidder: 'rubicon',
+ bidderRequestId: '15246a574e859f',
+ uspConsent: 'usp-context-string',
+ gdprConsent: {
+ consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA',
+ gdprApplies: true,
+ },
+ params: {
+ placement_id: '123',
+ account_id: 'test-account-id',
+ },
+ sizes: [[300, 250]],
+ ortb2: {
+ device: {
+ w: 1500,
+ h: 1000,
+ },
+ site: {
+ domain: 'test.com',
+ page: 'http://test.com',
+ },
+ },
+ userIdAsEids,
+ },
+ ];
+
+ const bidderRequest = {
+ ortb2: {
+ device: {
+ w: 1500,
+ h: 1000,
+ },
+ },
+ refererInfo: {
+ domain: 'test.com',
+ page: 'http://test.com',
+ ref: '',
+ },
+ };
+
+ const serverResponse = {
+ body: {
+ id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2',
+ seatbid: [
+ {
+ bid: [
+ {
+ id: 'test-bid-id',
+ price: 0.8,
+ adm: 'this is an ad',
+ adid: 'test-ad-id',
+ adomain: ['test.addomain.com'],
+ w: 300,
+ h: 250,
+ },
+ ],
+ seat: 'testBidder',
+ },
+ ],
+ cur: 'USD',
+ ext: {
+ sync: {
+ image: ['urlA?gdpr={{.GDPR}}'],
+ iframe: ['urlB'],
+ },
+ },
+ },
+ };
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: {
+ placement_id: '123',
+ },
+ };
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return false when required params are not passed', function () {
+ delete bid.params.placement_id;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ it('check request params with GDPR and USP', function () {
+ const request = spec.buildRequests(bidRequests, bidRequests[0]);
+ expect(JSON.parse(request[0].data).user.ext.consent).to.equal(
+ 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA'
+ );
+ expect(JSON.parse(request[0].data).regs.ext.gdpr).to.equal(1);
+ expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('usp-context-string');
+ });
+
+ it('check request params without GDPR', function () {
+ let bidRequestsWithoutGDPR = Object.assign({}, bidRequests[0]);
+ delete bidRequestsWithoutGDPR.gdprConsent;
+ const request = spec.buildRequests([bidRequestsWithoutGDPR], bidRequestsWithoutGDPR);
+ expect(JSON.parse(request[0].data).regs.ext.gdpr).to.be.undefined;
+ expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('usp-context-string');
+ });
+
+ it('should return correct storedrequest id if account_id is provided', function () {
+ const request = spec.buildRequests(bidRequests, bidRequests[0]);
+ expect(JSON.parse(request[0].data).ext.prebid.storedrequest.id).to.equal('test-account-id');
+ });
+
+ it('should return correct storedrequest id if account_id is not provided', function () {
+ let bidRequestsWithoutAccountId = Object.assign({}, bidRequests[0]);
+ delete bidRequestsWithoutAccountId.params.account_id;
+ const request = spec.buildRequests(
+ [bidRequestsWithoutAccountId],
+ bidRequestsWithoutAccountId
+ );
+ expect(JSON.parse(request[0].data).ext.prebid.storedrequest.id).to.equal('default');
+ });
+
+ it('validate generated params', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request[0].bidId).to.equal('22c4871113f461');
+ expect(JSON.parse(request[0].data).id).to.equal('15246a574e859f');
+ });
+
+ it('check if correct site object was added', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const siteObj = JSON.parse(request[0].data).site;
+
+ expect(siteObj.domain).to.equal('test.com');
+ expect(siteObj.page).to.equal('http://test.com');
+ expect(siteObj.ref).to.equal('');
+ });
+
+ it('check if correct device object was added', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const deviceObj = JSON.parse(request[0].data).device;
+
+ expect(deviceObj.w).to.equal(1500);
+ expect(deviceObj.h).to.equal(1000);
+ });
+
+ it('check if imp object was added', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(JSON.parse(request[0].data).imp).to.be.an('array');
+ });
+
+ it('should send "user.ext.eids" in the request for Prebid.js supported modules only', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(JSON.parse(request[0].data).user.ext.eids).to.deep.equal(userIdAsEids);
+ });
+
+ it('should send an undefined "user.ext.eids" in the request if userId module is unsupported', function () {
+ let bidRequestsUnsupportedUserIdModule = Object.assign({}, bidRequests[0]);
+ delete bidRequestsUnsupportedUserIdModule.userIdAsEids;
+ const request = spec.buildRequests(bidRequestsUnsupportedUserIdModule);
+
+ expect(JSON.parse(request[0].data).user.ext.eids).to.be.undefined;
+ });
+ });
+
+ describe('getUserSyncs', () => {
+ it('should return user sync', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true,
+ };
+ const responses = [
+ {
+ body: {
+ ext: {
+ responsetimemillis: {
+ 'test seat 1': 2,
+ 'test seat 2': 1,
+ },
+ },
+ },
+ },
+ ];
+ const gdprConsent = {
+ gdprApplies: 1,
+ consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig',
+ };
+ const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb';
+ const expectedUserSyncs = [
+ {
+ type: 'iframe',
+ url: 'https://cookie.stpd.cloud/sync?bidders=%5B%22test%20seat%201%22%2C%22test%20seat%202%22%5D&gdpr=1&gdpr_consent=dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig&usp_consent=mkjvbiniwot4827obfoy8sdg8203gb&type=iframe',
+ },
+ ];
+
+ const userSyncs = spec.getUserSyncs(syncOptions, responses, gdprConsent, uspConsent);
+
+ expect(userSyncs).to.deep.equal(expectedUserSyncs);
+ });
+
+ it('should return empty user syncs when responsetimemillis is not defined', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true,
+ };
+ const responses = [
+ {
+ body: {
+ ext: {},
+ },
+ },
+ ];
+ const gdprConsent = {
+ gdprApplies: 1,
+ consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig',
+ };
+ const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb';
+ const expectedUserSyncs = [];
+
+ const userSyncs = spec.getUserSyncs(syncOptions, responses, gdprConsent, uspConsent);
+
+ expect(userSyncs).to.deep.equal(expectedUserSyncs);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('should return empty array if error during parsing', () => {
+ const wrongServerResponse = 'wrong data';
+ let request = spec.buildRequests(bidRequests, bidRequests[0]);
+ let result = spec.interpretResponse(wrongServerResponse, request);
+
+ expect(result).to.be.instanceof(Array);
+ expect(result.length).to.equal(0);
+ });
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse(serverResponse, bidRequests[0]);
+ expect(result).to.be.an('array').with.lengthOf(1);
+ expect(result[0].requestId).to.equal('22c4871113f461');
+ expect(result[0].cpm).to.equal(0.8);
+ expect(result[0].width).to.equal(300);
+ expect(result[0].height).to.equal(250);
+ expect(result[0].creativeId).to.equal('test-bid-id');
+ expect(result[0].currency).to.equal('USD');
+ expect(result[0].netRevenue).to.equal(true);
+ expect(result[0].ttl).to.equal(360);
+ expect(result[0].ad).to.equal('this is an ad');
+ });
+ });
+
+ describe('onBidWon', function () {
+ it('should stop if bidder is not equal to BIDDER_CODE', function () {
+ const bid = {
+ bidder: 'rubicon',
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not provided', function () {
+ const bid = {
+ bidder: 'setupad',
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is empty array', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: [],
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not array', function () {
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: {},
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: 'test',
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: 1,
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: null,
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: undefined,
+ })
+ ).to.be.undefined;
+ });
+
+ it('should stop if bid.params.placement_id is not provided', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: [{ account_id: 'test' }],
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not provided and bid.bids is not an array', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: undefined,
+ bids: {},
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+ });
+});
diff --git a/test/spec/modules/sharethroughBidAdapter_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js
index 1bb6f898b81..ab099d87429 100644
--- a/test/spec/modules/sharethroughBidAdapter_spec.js
+++ b/test/spec/modules/sharethroughBidAdapter_spec.js
@@ -425,6 +425,41 @@ describe('sharethrough adapter spec', function () {
});
});
+ describe('dsa', () => {
+ it('should properly attach dsa information to the request when applicable', () => {
+ bidderRequest.ortb2 = {
+ regs: {
+ ext: {
+ dsa: {
+ 'dsarequired': 1,
+ 'pubrender': 0,
+ 'datatopub': 1,
+ 'transparency': [{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }, {
+ 'domain': 'bad-setup',
+ 'dsaparams': ['1', 3]
+ }]
+ }
+ }
+ }
+ }
+
+ const openRtbReq = spec.buildRequests(bidRequests, bidderRequest)[0].data;
+ expect(openRtbReq.regs.ext.dsa.dsarequired).to.equal(1);
+ expect(openRtbReq.regs.ext.dsa.pubrender).to.equal(0);
+ expect(openRtbReq.regs.ext.dsa.datatopub).to.equal(1);
+ expect(openRtbReq.regs.ext.dsa.transparency).to.deep.equal([{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }, {
+ 'domain': 'bad-setup',
+ 'dsaparams': ['1', 3]
+ }]);
+ });
+ });
+
describe('transaction id at the impression level', () => {
it('should include transaction id when provided', () => {
const requests = spec.buildRequests(bidRequests, bidderRequest);
diff --git a/test/spec/modules/smartyadsBidAdapter_spec.js b/test/spec/modules/smartyadsBidAdapter_spec.js
index 458ccc37759..1b592e142c3 100644
--- a/test/spec/modules/smartyadsBidAdapter_spec.js
+++ b/test/spec/modules/smartyadsBidAdapter_spec.js
@@ -61,7 +61,7 @@ describe('SmartyadsAdapter', function () {
it('Returns valid data if array of bids is valid', function () {
let data = serverRequest.data;
expect(data).to.be.an('object');
- expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'coppa');
+ expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'coppa', 'eeid', 'ifa');
expect(data.deviceWidth).to.be.a('number');
expect(data.deviceHeight).to.be.a('number');
expect(data.coppa).to.be.a('number');
diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js
index 973e90abd5a..d0363eab144 100644
--- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js
+++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js
@@ -12,8 +12,8 @@ let constants = require('src/constants.json');
/**
* Emit analytics events
- * @param {Array} eventArr - array of objects to define the events that will fire
- * @param {object} eventObj - key is eventType, value is event
+ * @param {Array} eventType - array of objects to define the events that will fire
+ * @param {object} event - key is eventType, value is event
* @param {string} auctionId - the auction id to attached to the events
*/
function emitEvent(eventType, event, auctionId) {
diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js
index f165a6da6d1..274192d14a7 100644
--- a/test/spec/modules/sovrnBidAdapter_spec.js
+++ b/test/spec/modules/sovrnBidAdapter_spec.js
@@ -530,6 +530,45 @@ describe('sovrnBidAdapter', function() {
expect(impression.bidfloor).to.equal(2.00)
})
+ it('floor should be undefined if there is no floor from the floor module and params', function() {
+ const floorBid = {
+ ...baseBidRequest
+ }
+ floorBid.params = {
+ tagid: 1234
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
+ it('floor should be undefined if there is incorrect floor value from the floor module', function() {
+ const floorBid = {
+ ...baseBidRequest,
+ getFloor: () => ({currency: 'USD', floor: 'incorrect_value'}),
+ params: {
+ tagid: 1234
+ }
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
+ it('floor should be undefined if there is incorrect floor value from the params', function() {
+ const floorBid = {
+ ...baseBidRequest,
+ getFloor: () => ({})
+ }
+ floorBid.params = {
+ tagid: 1234,
+ bidfloor: 'incorrect_value'
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
describe('First Party Data', function () {
it('should provide first party data if provided', function() {
const ortb2 = {
diff --git a/test/spec/modules/sspBCBidAdapter_spec.js b/test/spec/modules/sspBCBidAdapter_spec.js
index 71619424e4b..2f5fe104eb1 100644
--- a/test/spec/modules/sspBCBidAdapter_spec.js
+++ b/test/spec/modules/sspBCBidAdapter_spec.js
@@ -638,7 +638,7 @@ describe('SSPBC adapter', function () {
expect(adcode).to.be.a('string');
expect(adcode).to.contain('window.rekid');
expect(adcode).to.contain('window.mcad');
- expect(adcode).to.contain('window.gdpr');
+ expect(adcode).to.contain('window.tcString');
expect(adcode).to.contain('window.page');
expect(adcode).to.contain('window.requestPVID');
});
diff --git a/test/spec/modules/stnBidAdapter_spec.js b/test/spec/modules/stnBidAdapter_spec.js
new file mode 100644
index 00000000000..deba87baac2
--- /dev/null
+++ b/test/spec/modules/stnBidAdapter_spec.js
@@ -0,0 +1,625 @@
+import { expect } from 'chai';
+import { spec } from 'modules/stnBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import { config } from 'src/config.js';
+import { BANNER, VIDEO } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
+
+const ENDPOINT = 'https://hb.stngo.com/hb-multi';
+const TEST_ENDPOINT = 'https://hb.stngo.com/hb-multi-test';
+const TTL = 360;
+/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
+
+describe('stnAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'org': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[640, 480]],
+ 'context': 'instream',
+ 'plcmt': 1
+ }
+ },
+ 'vastXml': '"..."'
+ },
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '""'
+ }
+ ];
+
+ const testModeBidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001',
+ 'testMode': true
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 2,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'stn',
+ }
+ const placementId = '12345678';
+ const api = [1, 2];
+ const mimes = ['application/javascript', 'video/mp4', 'video/quicktime'];
+ const protocols = [2, 3, 5, 6];
+
+ it('sends the placementId to ENDPOINT via POST', function () {
+ bidRequests[0].params.placementId = placementId;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].placementId).to.equal(placementId);
+ });
+
+ it('sends the plcmt to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].plcmt).to.equal(1);
+ });
+
+ it('sends the is_wrapper parameter to ENDPOINT via POST', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('is_wrapper');
+ expect(request.data.params.is_wrapper).to.equal(false);
+ });
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('sends bid request to TEST ENDPOINT via POST', function () {
+ const request = spec.buildRequests(testModeBidRequests, bidderRequest);
+ expect(request.url).to.equal(TEST_ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
+ });
+
+ it('should send the correct supported api array', function () {
+ bidRequests[0].mediaTypes.video.api = api;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].api).to.be.an('array');
+ expect(request.data.bids[0].api).to.eql([1, 2]);
+ });
+
+ it('should send the correct mimes array', function () {
+ bidRequests[1].mediaTypes.banner.mimes = mimes;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[1].mimes).to.be.an('array');
+ expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']);
+ });
+
+ it('should send the correct protocols array', function () {
+ bidRequests[0].mediaTypes.video.protocols = protocols;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].protocols).to.be.an('array');
+ expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]);
+ });
+
+ it('should send the correct sizes array', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sizes).to.be.an('array');
+ expect(request.data.bids[0].sizes).to.equal(bidRequests[0].sizes)
+ expect(request.data.bids[1].sizes).to.be.an('array');
+ expect(request.data.bids[1].sizes).to.equal(bidRequests[1].sizes)
+ });
+
+ it('should send the correct media type', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].mediaType).to.equal(VIDEO)
+ expect(request.data.bids[1].mediaType).to.equal(BANNER)
+ });
+
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
+ };
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
+
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
+
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
+ });
+
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
+
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
+ });
+
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
+
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
+ });
+
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'test-consent-string', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'test-consent-string');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
+
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
+
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
+
+ it('should check sua param in bid request', function() {
+ const sua = {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': ['12', '4', '0']
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': [ '12', '4', '0' ]
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [{
+ cpm: 12.5,
+ vastXml: '',
+ width: 640,
+ height: 480,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: VIDEO
+ },
+ {
+ cpm: 12.5,
+ ad: '""',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER
+ }]
+ };
+
+ const expectedVideoResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: VIDEO,
+ meta: {
+ mediaType: VIDEO,
+ advertiserDomains: ['abc.com']
+ },
+ vastXml: '',
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ advertiserDomains: ['abc.com']
+ },
+ ad: '""'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedVideoResponse));
+ expect(Object.keys(result[1])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+
+ it('video type should have vastXml key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[0].vastXml).to.equal(expectedVideoResponse.vastXml)
+ });
+
+ it('banner type should have ad key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[1].ad).to.equal(expectedBannerResponse.ad)
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
+
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
+ });
+ })
+
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ })
+ })
+});
diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js
index 8a121865cf2..ca09fbbbcc9 100644
--- a/test/spec/modules/taboolaBidAdapter_spec.js
+++ b/test/spec/modules/taboolaBidAdapter_spec.js
@@ -157,7 +157,7 @@ describe('Taboola Adapter', function () {
spec.onBidderError({error, bidderRequest});
expect(server.requests[0].method).to.equal('POST');
expect(server.requests[0].url).to.equal(EVENT_ENDPOINT + '/bidError');
- expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal(error, bidderRequest);
+ expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal({error, bidderRequest});
});
});
@@ -398,6 +398,30 @@ describe('Taboola Adapter', function () {
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
expect(res.data.ext.example).to.deep.equal(bidderRequest.ortb2.ext.example);
});
+
+ it('should pass additional parameter in request for topics', function () {
+ const ortb2 = {
+ ...commonBidderRequest,
+ ortb2: {
+ user: {
+ data: {
+ segment: [
+ {
+ id: '243'
+ }
+ ],
+ name: 'pa.taboola.com',
+ ext: {
+ segclass: '4',
+ segtax: 601
+ }
+ }
+ }
+ }
+ }
+ const res = spec.buildRequests([defaultBidRequest], {...ortb2})
+ expect(res.data.user.data).to.deep.equal(ortb2.ortb2.user.data);
+ });
});
describe('handle privacy segments when building request', function () {
@@ -668,6 +692,181 @@ describe('Taboola Adapter', function () {
}
};
+ const serverResponseWithPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"סגור","goto":"עבור לדף"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"לקריאת התוכן הבא"},"time-ago":{"now":"עכשיו","today":"היום","yesterday":"אתמול","minutes":"לפני {0} דקות","hour":"לפני שעה","hours":"לפני {0} שעות","days":"לפני {0} ימים"},"explore-more":{"TITLE_TEXT":"המשיכו לקרוא","POPUP_TEXT":"אל תפספסו הזדמנות לקרוא עוד תוכן מעולה, רגע לפני שתעזבו"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ 'origin': 'https://pa.taboola.com',
+ 'buyerdata': '{\"seller\":\"pa.taboola.com\",\"resolveToConfig\":false,\"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\"}},\"decisionLogicUrl\":\"https://pa.taboola.com/score/decisionLogic.js\",\"sellerTimeout\":100,\"interestGroupBuyers\":[\"https://pa.taboola.com\"],\"perBuyerTimeouts\":{\"*\":50}}'
+ }
+ ]
+ }
+ ]
+ }
+ }
+ };
+
+ const serverResponseWithPartialPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"סגור","goto":"עבור לדף"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"לקריאת התוכן הבא"},"time-ago":{"now":"עכשיו","today":"היום","yesterday":"אתמול","minutes":"לפני {0} דקות","hour":"לפני שעה","hours":"לפני {0} שעות","days":"לפני {0} ימים"},"explore-more":{"TITLE_TEXT":"המשיכו לקרוא","POPUP_TEXT":"אל תפספסו הזדמנות לקרוא עוד תוכן מעולה, רגע לפני שתעזבו"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ 'origin': 'https://pa.taboola.com',
+ 'buyerdata': '{}'
+ }
+ ]
+ }
+ ]
+ }
+ }
+ };
+
+ const serverResponseWithWrongPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"סגור","goto":"עבור לדף"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"לקריאת התוכן הבא"},"time-ago":{"now":"עכשיו","today":"היום","yesterday":"אתמול","minutes":"לפני {0} דקות","hour":"לפני שעה","hours":"לפני {0} שעות","days":"לפני {0} ימים"},"explore-more":{"TITLE_TEXT":"המשיכו לקרוא","POPUP_TEXT":"אל תפספסו הזדמנות לקרוא עוד תוכן מעולה, רגע לפני שתעזבו"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ }
+ ]
+ }
+ ]
+ }
+ }
+ };
+
+ const serverResponseWithEmptyIgbidWIthWrongPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"סגור","goto":"עבור לדף"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"לקריאת התוכן הבא"},"time-ago":{"now":"עכשיו","today":"היום","yesterday":"אתמול","minutes":"לפני {0} דקות","hour":"לפני שעה","hours":"לפני {0} שעות","days":"לפני {0} ימים"},"explore-more":{"TITLE_TEXT":"המשיכו לקרוא","POPUP_TEXT":"אל תפספסו הזדמנות לקרוא עוד תוכן מעולה, רגע לפני שתעזבו"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ }
+ ]
+ }
+ }
+ };
+
it('should return empty array if no valid bids', function () {
const res = spec.interpretResponse(serverResponse, [])
expect(res).to.be.an('array').that.is.empty
@@ -824,6 +1023,181 @@ describe('Taboola Adapter', function () {
expect(res).to.deep.equal(expectedRes)
});
+ 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
+ },
+ }
+ ],
+ 'fledgeAuctionConfigs': [
+ {
+ '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
+ },
+ }
+ ],
+ 'fledgeAuctionConfigs': [
+ {
+ '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 f26081b0cef..1e044651315 100644
--- a/test/spec/modules/teadsBidAdapter_spec.js
+++ b/test/spec/modules/teadsBidAdapter_spec.js
@@ -1,7 +1,7 @@
import {expect} from 'chai';
import {spec, storage} from 'modules/teadsBidAdapter.js';
import {newBidder} from 'src/adapters/bidderFactory.js';
-import { off } from '../../../src/events';
+import * as autoplay from 'libraries/autoplayDetection/autoplay.js'
const ENDPOINT = 'https://a.teads.tv/hb/bid-request';
const AD_SCRIPT = '"';
@@ -1059,7 +1059,8 @@ describe('teadsBidAdapter', () => {
'ttl': 360,
'width': 300,
'creativeId': 'er2ee',
- 'placementId': 34
+ 'placementId': 34,
+ 'needAutoplay': true
}, {
'ad': AD_SCRIPT,
'cpm': 0.5,
@@ -1070,6 +1071,7 @@ describe('teadsBidAdapter', () => {
'width': 350,
'creativeId': 'fs3ff',
'placementId': 34,
+ 'needAutoplay': false,
'dealId': 'ABC_123',
'ext': {
'dsa': {
@@ -1132,6 +1134,70 @@ describe('teadsBidAdapter', () => {
expect(result).to.eql(expectedResponse);
});
+ it('should filter bid responses with needAutoplay:true when autoplay is disabled', function() {
+ let bids = {
+ 'body': {
+ 'responses': [{
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.5,
+ 'currency': 'USD',
+ 'height': 250,
+ 'bidId': '3ede2a3fa0db94',
+ 'ttl': 360,
+ 'width': 300,
+ 'creativeId': 'er2ee',
+ 'placementId': 34,
+ 'needAutoplay': true
+ }, {
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.5,
+ 'currency': 'USD',
+ 'height': 200,
+ 'bidId': '4fef3b4gb1ec15',
+ 'ttl': 360,
+ 'width': 350,
+ 'creativeId': 'fs3ff',
+ 'placementId': 34,
+ 'needAutoplay': false
+ }, {
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.7,
+ 'currency': 'USD',
+ 'height': 600,
+ 'bidId': 'a987fbc961d',
+ 'ttl': 12,
+ 'width': 300,
+ 'creativeId': 'awuygfd',
+ 'placementId': 12,
+ 'needAutoplay': true
+ }]
+ }
+ };
+ let expectedResponse = [{
+ 'cpm': 0.5,
+ 'width': 350,
+ 'height': 200,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'meta': {
+ advertiserDomains: [],
+ },
+ 'ttl': 360,
+ 'ad': AD_SCRIPT,
+ 'requestId': '4fef3b4gb1ec15',
+ 'creativeId': 'fs3ff',
+ 'placementId': 34
+ }
+ ]
+ ;
+
+ const isAutoplayEnabledStub = sinon.stub(autoplay, 'isAutoplayEnabled');
+ isAutoplayEnabledStub.returns(false);
+ let result = spec.interpretResponse(bids);
+ isAutoplayEnabledStub.restore();
+ expect(result).to.eql(expectedResponse);
+ });
+
it('handles nobid responses', function() {
let bids = {
'body': {
diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js
index 275b9b3bfee..851425574d0 100644
--- a/test/spec/modules/tripleliftBidAdapter_spec.js
+++ b/test/spec/modules/tripleliftBidAdapter_spec.js
@@ -736,258 +736,83 @@ describe('triplelift adapter', function () {
});
it('should add tdid to the payload if included', function () {
- const id = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- bidRequests[0].userId.tdid = id;
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adserver.org', uids: [{id, ext: {rtiPartner: 'TDID'}}]}]}});
- });
-
- it('should add idl_env to the payload if included', function () {
- const id = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- bidRequests[0].userId.idl_env = id;
+ const tdid = '6bca7f6b-a98a-46c0-be05-6020f7604598';
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'adserver.org',
+ uids: [
+ {
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID'
+ },
+ id: tdid
+ }
+ ]
+ },
+ ];
const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
const payload = request.data;
expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'liveramp.com', uids: [{id, ext: {rtiPartner: 'idl'}}]}]}});
+ expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adserver.org', uids: [{id: tdid, atype: 1, ext: {rtiPartner: 'TDID'}}]}]}});
});
it('should add criteoId to the payload if included', function () {
const id = '53e30ea700424f7bbdd793b02abc5d7';
- bidRequests[0].userId.criteoId = id;
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'criteo.com', uids: [{id, ext: {rtiPartner: 'criteoId'}}]}]}});
- });
-
- it('should add adqueryId to the payload if included', function () {
- const id = '%7B%22qid%22%3A%229c985f8cc31d9b3c000d%22%7D';
- bidRequests[0].userIdAsEids = [{ source: 'adquery.io', uids: [{ id }] }];
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adquery.io', uids: [{id, ext: {rtiPartner: 'adquery.io'}}]}]}});
- });
-
- it('should add amxRtbId to the payload if included', function () {
- const id = 'Ok9JQkBM-UFlAXEZQ-UUNBQlZOQzgrUFhW-UUNBQkRQTUBPQVpVWVxNXlZUUF9AUFhAUF9PXFY/';
- bidRequests[0].userIdAsEids = [{ source: 'amxdt.net', uids: [{ id }] }];
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxdt.net', uids: [{id, ext: {rtiPartner: 'amxdt.net'}}]}]}});
- });
-
- it('should add tdid, idl_env and criteoId to the payload if both are included', function () {
- const tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- const idlEnvId = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- bidRequests[0].userId.tdid = tdidId;
- bidRequests[0].userId.idl_env = idlEnvId;
- bidRequests[0].userId.criteoId = criteoId;
-
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
-
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
- {
- source: 'liveramp.com',
- uids: [
- {
- id: idlEnvId,
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'criteo.com',
+ uids: [
{
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'criteoId'
+ },
+ id: id
}
]
- }
- });
- });
-
- it('should consolidate user ids from multiple bid requests', function () {
- const tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- const idlEnvId = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- const pubcid = '3261d8ad-435d-481d-abd1-9f1a9ec99f0e';
-
- const bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
+ },
];
-
- const request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
+ const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
const payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
- {
- source: 'liveramp.com',
- uids: [
- {
- id: idlEnvId,
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
- {
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
- },
- {
- source: 'pubcid.org',
- uids: [
- {
- id: '3261d8ad-435d-481d-abd1-9f1a9ec99f0e',
- ext: { rtiPartner: 'pubcid' }
- }
- ]
- }
- ]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(4);
+ expect(payload).to.exist;
+ expect(payload.user).to.deep.equal({ext: {eids: [{source: 'criteo.com', uids: [{id: id, atype: 1, ext: {rtiPartner: 'criteoId'}}]}]}});
});
- it('should remove malformed ids that would otherwise break call', function () {
- let tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- let idlEnvId = null; // fail; can't be null
- let criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- let pubcid = ''; // fail; can't be empty string
-
- let bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
- ];
-
- let request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- let payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
+ it('should add tdid and criteoId to the payload if both are included', function () {
+ const tdid = '6bca7f6b-a98a-46c0-be05-6020f7604598';
+ const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'adserver.org',
+ uids: [
{
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID'
+ },
+ id: tdid
}
]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(2);
-
- tdidId = {}; // fail; can't be empty object
- idlEnvId = { id: '987654' }; // pass
- criteoId = [{ id: '123456' }]; // fail; can't be an array
- pubcid = '3261d8ad-435d-481d-abd1-9f1a9ec99f0e'; // pass
-
- bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
- ];
-
- request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'liveramp.com',
- uids: [
- {
- id: '987654',
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
+ },
+ {
+ source: 'criteo.com',
+ uids: [
{
- source: 'pubcid.org',
- uids: [
- {
- id: pubcid,
- ext: { rtiPartner: 'pubcid' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'criteoId'
+ },
+ id: criteoId
}
]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(2);
-
- tdidId = { id: '987654' }; // pass
- idlEnvId = { id: 987654 }; // fail; can't be an int
- criteoId = '53e30ea700424f7bbdd793b02abc5d7'; // pass
- pubcid = { id: '' }; // fail; can't be an empty string
-
- bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
+ },
];
- request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- payload = request.data;
+ const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
+ const payload = request.data;
+ expect(payload).to.exist;
expect(payload.user).to.deep.equal({
ext: {
eids: [
@@ -995,7 +820,8 @@ describe('triplelift adapter', function () {
source: 'adserver.org',
uids: [
{
- id: '987654',
+ id: tdid,
+ atype: 1,
ext: { rtiPartner: 'TDID' }
}
],
@@ -1005,6 +831,7 @@ describe('triplelift adapter', function () {
uids: [
{
id: criteoId,
+ atype: 1,
ext: { rtiPartner: 'criteoId' }
}
]
diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js
index 18f49f4943e..1e909d79ed4 100644
--- a/test/spec/modules/userId_spec.js
+++ b/test/spec/modules/userId_spec.js
@@ -12,6 +12,7 @@ import {
setSubmoduleRegistry,
syncDelay,
} from 'modules/userId/index.js';
+import {UID1_EIDS} from 'libraries/uid1Eids/uid1Eids.js';
import {createEidsArray, EID_CONFIG} from 'modules/userId/eids.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
@@ -99,6 +100,25 @@ describe('User ID', function () {
}
}
+ function createMockEid(name, source) {
+ return {
+ [name]: {
+ source: source || `${name}Source`,
+ atype: 3,
+ getValue: function(data) {
+ if (data.id) {
+ return data.id;
+ } else {
+ return data;
+ }
+ },
+ getUidExt: function(data) {
+ return data.ext
+ }
+ }
+ }
+ }
+
function getAdUnitMock(code = 'adUnit-code') {
return {
code,
@@ -644,10 +664,10 @@ describe('User ID', function () {
it('pbjs.getUserIdsAsEids should prioritize user ids according to config available to core', () => {
init(config);
setSubmoduleRegistry([
- createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}),
- createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}),
- createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}),
- createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}})
+ createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}, null, createMockEid('uid2')),
+ createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}, null, createMockEid('pubcid')),
+ createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}, null, {...createMockEid('uid2'), ...createMockEid('merkleId'), ...createMockEid('lipb')}),
+ createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}}, null, createMockEid('merkleId'))
]);
config.setConfig({
userSync: {
@@ -679,6 +699,38 @@ describe('User ID', function () {
});
});
+ it('pbjs.getUserIdsAsEids should prioritize the uid1 according to config available to core', () => {
+ init(config);
+ setSubmoduleRegistry([
+ createMockIdSubmodule('mockId1Module', {id: {tdid: {id: 'uid1_value'}}}, null, UID1_EIDS),
+ createMockIdSubmodule('mockId2Module', {id: {tdid: {id: 'uid1Id_value_from_mockId2Module'}}}, null, UID1_EIDS),
+ createMockIdSubmodule('mockId3Module', {id: {tdid: {id: 'uid1Id_value_from_mockId3Module'}}}, null, UID1_EIDS)
+ ]);
+ config.setConfig({
+ userSync: {
+ idPriority: {
+ tdid: ['mockId2Module', 'mockId3Module', 'mockId1Module']
+ },
+ auctionDelay: 10, // with auctionDelay > 0, no auction is needed to complete init
+ userIds: [
+ { name: 'mockId1Module' },
+ { name: 'mockId2Module' },
+ { name: 'mockId3Module' }
+ ]
+ }
+ });
+
+ const ids = {
+ 'tdid': { id: 'uid1Id_value_from_mockId2Module' },
+ };
+
+ return getGlobal().getUserIdsAsync().then(() => {
+ const eids = getGlobal().getUserIdsAsEids();
+ const expected = createEidsArray(ids);
+ expect(eids).to.deep.equal(expected);
+ })
+ });
+
describe('EID updateConfig', () => {
function mockSubmod(name, eids) {
return createMockIdSubmodule(name, null, null, eids);
@@ -3554,11 +3606,16 @@ describe('User ID', function () {
it('pbjs.getUserIdsAsEidBySource with priority config available to core', () => {
init(config);
+ const uid2Eids = createMockEid('uid2', 'uidapi.com')
+ const pubcEids = createMockEid('pubcid', 'pubcid.org')
+ const liveIntentEids = createMockEid('lipb', 'liveintent.com')
+ const merkleEids = createMockEid('merkleId', 'merkleinc.com')
+
setSubmoduleRegistry([
- createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}),
- createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}),
- createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}),
- createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}})
+ createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}, null, uid2Eids),
+ createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}, null, {...pubcEids, ...liveIntentEids}),
+ createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}, null, {...uid2Eids, ...pubcEids, ...liveIntentEids}),
+ createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}}, null, merkleEids)
]);
config.setConfig({
userSync: {
diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js
index bc5165c8d54..5515002a054 100644
--- a/test/spec/modules/vidazooBidAdapter_spec.js
+++ b/test/spec/modules/vidazooBidAdapter_spec.js
@@ -19,6 +19,7 @@ import {version} from 'package.json';
import {useFakeTimers} from 'sinon';
import {BANNER, VIDEO} from '../../../src/mediaTypes';
import {config} from '../../../src/config';
+import {deepSetValue} from 'src/utils.js';
export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId'];
@@ -108,7 +109,19 @@ const BIDDER_REQUEST = {
'ortb2': {
'site': {
'cat': ['IAB2'],
- 'pagecat': ['IAB2-2']
+ 'pagecat': ['IAB2-2'],
+ 'content': {
+ 'data': [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }]
+ }
},
'regs': {
'gpp': 'gpp_string',
@@ -131,6 +144,15 @@ const BIDDER_REQUEST = {
'bitness': '64',
'architecture': ''
}
+ },
+ user: {
+ data: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
}
},
};
@@ -318,6 +340,23 @@ describe('VidazooBidAdapter', function () {
'bitness': '64',
'architecture': ''
},
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
uqs: getTopWindowQueryParams(),
isStorageAllowed: true,
@@ -340,7 +379,8 @@ describe('VidazooBidAdapter', function () {
}
}
}
- });
+ })
+ ;
});
it('should build banner request for each size', function () {
@@ -405,6 +445,23 @@ describe('VidazooBidAdapter', function () {
gpid: '1234567890',
cat: ['IAB2'],
pagecat: ['IAB2-2'],
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
webSessionId: webSessionId
}
});
@@ -478,6 +535,23 @@ describe('VidazooBidAdapter', function () {
gpid: '1234567890',
cat: ['IAB2'],
pagecat: ['IAB2-2'],
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
webSessionId: webSessionId
};
@@ -523,6 +597,15 @@ 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.fledgeEnabled = true;
+ deepSetValue(bidderRequest, 'ortb2Imp.ext.ae', 1);
+ const requests = adapter.buildRequests([BID], bidderRequest);
+ expect(requests[0].data.fledge).to.equal(1);
+ });
+
after(function () {
$$PREBID_GLOBAL$$.bidderSettings = {};
config.resetConfig();
diff --git a/test/spec/modules/weboramaRtdProvider_spec.js b/test/spec/modules/weboramaRtdProvider_spec.js
index 7de8474d7c9..d562d9ffd13 100644
--- a/test/spec/modules/weboramaRtdProvider_spec.js
+++ b/test/spec/modules/weboramaRtdProvider_spec.js
@@ -48,6 +48,120 @@ describe('weboramaRtdProvider', function() {
};
expect(weboramaSubmodule.init(moduleConfig)).to.equal(true);
});
+
+ it('instantiate with empty sfbxLiteData should return true', function() {
+ const moduleConfig = {
+ params: {
+ sfbxLiteDataConf: {},
+ }
+ };
+ expect(weboramaSubmodule.init(moduleConfig)).to.equal(true);
+ });
+
+ describe('webo user data should check gdpr consent', function() {
+ it('should initialize if gdpr does not applies', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: false,
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(true);
+ });
+ it('should initialize if gdpr applies and consent is ok', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: true,
+ 3: true,
+ 4: true,
+ 5: true,
+ 6: true,
+ 9: true,
+ },
+ },
+ specialFeatureOptins: {
+ 1: true,
+ },
+ vendor: {
+ consents: {
+ 284: true,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(true);
+ });
+ it('should NOT initialize if gdpr applies and consent is nok: miss consent vendor id', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: true,
+ 3: true,
+ 4: true,
+ },
+ },
+ specialFeatureOptins: {},
+ vendor: {
+ consents: {
+ 284: false,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(false);
+ });
+ it('should NOT initialize if gdpr applies and consent is nok: miss one purpose id', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: false,
+ 3: true,
+ 4: true,
+ },
+ },
+ specialFeatureOptins: {},
+ vendor: {
+ consents: {
+ 284: true,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(false);
+ });
+ });
});
describe('Handle Set Targeting and Bid Request', function() {
diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js
index 68cf3459c5f..3c842c3a308 100644
--- a/test/spec/modules/yieldmoBidAdapter_spec.js
+++ b/test/spec/modules/yieldmoBidAdapter_spec.js
@@ -512,20 +512,6 @@ describe('YieldmoAdapter', function () {
expect(buildVideoBidAndGetVideoParam().mimes).to.deep.equal(['video/mkv']);
});
- it('should validate protocol in video bid request', function () {
- expect(
- spec.isBidRequestValid(
- mockVideoBid({}, {}, { protocols: [2, 3, 11] })
- )
- ).to.be.true;
-
- expect(
- spec.isBidRequestValid(
- mockVideoBid({}, {}, { protocols: [2, 3, 10] })
- )
- ).to.be.false;
- });
-
describe('video.skip state check', () => {
it('should not set video.skip if neither *.video.skip nor *.video.skippable is present', function () {
utils.deepAccess(videoBid, 'mediaTypes.video')['skippable'] = false;
diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js
index 81617b93d3c..f9cfe2dde6a 100644
--- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js
+++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js
@@ -59,7 +59,7 @@ describe('Zeta Ssp Bid Adapter', function () {
sid: 'publisherId',
tagid: 'test_tag_id',
site: {
- page: 'testPage'
+ page: 'http://www.zetaglobal.com/page?param=value'
},
app: {
bundle: 'testBundle'
@@ -209,6 +209,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '12345',
seatbid: [
{
+ seat: '1',
bid: [
{
id: 'auctionId',
@@ -234,7 +235,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '123',
site: {
id: 'SITE_ID',
- page: 'page.com',
+ page: 'http://www.zetaglobal.com/page?param=value',
domain: 'domain.com'
},
user: {
@@ -262,7 +263,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '123',
site: {
id: 'SITE_ID',
- page: 'page.com',
+ page: 'http://www.zetaglobal.com/page?param=value',
domain: 'domain.com'
},
user: {
@@ -311,7 +312,7 @@ describe('Zeta Ssp Bid Adapter', function () {
it('Test page and domain in site', function () {
const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
const payload = JSON.parse(request.data);
- expect(payload.site.page).to.eql('http://www.zetaglobal.com/page?param=value');
+ expect(payload.site.page).to.eql('zetaglobal.com/page');
expect(payload.site.domain).to.eql('zetaglobal.com');
});
@@ -601,6 +602,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(BANNER);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.be.undefined;
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response default mediaType:video', function () {
@@ -610,6 +612,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(VIDEO);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response mediaType:video from ext param', function () {
@@ -624,6 +627,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(VIDEO);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response mediaType:banner from ext param', function () {
@@ -638,6 +642,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(BANNER);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.be.undefined;
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test provide segments into the request', function () {