diff --git a/integrationExamples/gpt/adloox.html b/integrationExamples/gpt/adloox.html
index fd61267479d..78fba71f774 100644
--- a/integrationExamples/gpt/adloox.html
+++ b/integrationExamples/gpt/adloox.html
@@ -147,8 +147,13 @@
realTimeData: {
auctionDelay: AUCTION_DELAY,
dataProviders: [
+ {
+ name: 'intersection',
+ waitForIt: true
+ },
{
name: 'adloox',
+ waitForIt: true,
params: { // optional, defaults shown
thresholds: [ 50, 60, 70, 80, 90 ],
slotinpath: false
diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js
index 4f86a914982..12fd50c6636 100644
--- a/modules/adagioBidAdapter.js
+++ b/modules/adagioBidAdapter.js
@@ -669,10 +669,8 @@ function autoFillParams(bid) {
}
// extra params
- setExtraParam(bid, 'environment');
setExtraParam(bid, 'pagetype');
setExtraParam(bid, 'category');
- setExtraParam(bid, 'subcategory');
}
function getPageDimensions() {
@@ -1094,8 +1092,6 @@ export const spec = {
bidObj.placement = bidReq.params.placement;
bidObj.pagetype = bidReq.params.pagetype;
bidObj.category = bidReq.params.category;
- bidObj.subcategory = bidReq.params.subcategory;
- bidObj.environment = bidReq.params.environment;
}
bidResponses.push(bidObj);
});
diff --git a/modules/adagioBidAdapter.md b/modules/adagioBidAdapter.md
index 9b48caa8233..b804a72fea9 100644
--- a/modules/adagioBidAdapter.md
+++ b/modules/adagioBidAdapter.md
@@ -17,12 +17,10 @@ Below, the list of Adagio params and where they can be set.
| Param name | Global config | AdUnit config |
| ---------- | ------------- | ------------- |
| siteId | x |
-| organizationId (obsolete) | | x
-| site (obsolete) | | x
+| organizationId * | | x
+| site * | | x
| pagetype | x | x
-| environment | x | x
| category | x | x
-| subcategory | x | x
| useAdUnitCodeAsAdUnitElementId | x | x
| useAdUnitCodeAsPlacement | x | x
| placement | | x
@@ -31,6 +29,8 @@ Below, the list of Adagio params and where they can be set.
| video | | x
| native | | x
+_* These params are deprecated in favor the Global configuration setup, see below._
+
### Global configuration
The global configuration is used to store params once instead of duplicate them to each adUnit. The values will be used as "params" in the ad-request.
@@ -49,9 +49,7 @@ pbjs.setConfig({
// - underscores `_`
// Also, each param can have at most 50 unique active values (case-insensitive).
pagetype: 'article', // Highly recommended. The pagetype describes what kind of content will be present in the page.
- environment: 'mobile', // Recommended. Environment where the page is displayed.
category: 'sport', // Recommended. Category of the content displayed in the page.
- subcategory: 'handball', // Optional. Subcategory of the content displayed in the page.
useAdUnitCodeAsAdUnitElementId: false, // Optional. Use it by-pass adUnitElementId and use the adUnit code as value
useAdUnitCodeAsPlacement: false, // Optional. Use it to by-pass placement and use the adUnit code as value
},
@@ -62,9 +60,7 @@ pbjs.setConfig({
Adagio will use FPD data as fallback for the params below:
- pagetype
-- environment
- category
-- subcategory
If the FPD value is an array, the 1st value of this array will be used.
@@ -107,9 +103,7 @@ var adUnits = [
debug: true,
adagio: {
pagetype: 'article',
- environment: 'mobile',
category: 'sport',
- subcategory: 'handball',
useAdUnitCodeAsAdUnitElementId: false,
useAdUnitCodeAsPlacement: false,
}
@@ -208,12 +202,6 @@ var adUnits = [
return bidResponse.site;
}
},
- {
- key: "environment",
- val: function (bidResponse) {
- return bidResponse.environment;
- }
- },
{
key: "placement",
val: function (bidResponse) {
@@ -231,12 +219,6 @@ var adUnits = [
val: function (bidResponse) {
return bidResponse.category;
}
- },
- {
- key: "subcategory",
- val: function (bidResponse) {
- return bidResponse.subcategory;
- }
}
]
}
diff --git a/modules/adlooxAnalyticsAdapter.md b/modules/adlooxAnalyticsAdapter.md
index 203b118652e..d77ee25ab5f 100644
--- a/modules/adlooxAnalyticsAdapter.md
+++ b/modules/adlooxAnalyticsAdapter.md
@@ -34,19 +34,21 @@ When tracking video you have two options:
To view an [example of an Adloox integration](../integrationExamples/gpt/adloox.html):
- gulp serve --nolint --notest --modules=gptPreAuction,categoryTranslation,dfpAdServerVideo,rtdModule,instreamTracking,rubiconBidAdapter,spotxBidAdapter,adlooxAnalyticsAdapter,adlooxAdServerVideo,adlooxRtdProvider
+ gulp serve --nolint --notest --modules=gptPreAuction,categoryTranslation,dfpAdServerVideo,intersectionRtdProvider,rtdModule,instreamTracking,rubiconBidAdapter,spotxBidAdapter,adlooxAnalyticsAdapter,adlooxAdServerVideo,adlooxRtdProvider
**N.B.** `categoryTranslation` is required by `dfpAdServerVideo` that otherwise causes a JavaScript console warning
+**N.B.** `intersectionRtdProvider` is used by `adlooxRtdProvider` to provide (above-the-fold) ATF measurement, if not enabled the `atf` segment will not be available
+
Now point your browser at: http://localhost:9999/integrationExamples/gpt/adloox.html?pbjs_debug=true
### Public Example
-The example is published publically at: https://storage.googleapis.com/adloox-ads-js-test/prebid.html?pbjs_debug=true
+The example is published publicly at: https://storage.googleapis.com/adloox-ads-js-test/prebid.html?pbjs_debug=true
**N.B.** this will show a [CORS error](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) for the request `https://p.adlooxtracking.com/q?...` that is safe to ignore on the public example page; it is related to the [RTD integration](./adlooxRtdProvider.md) which requires pre-registration of your sites
-It is recommended you use [Google Chrome's 'Local Overrides' located in the Developer Tools panel](https://www.trysmudford.com/blog/chrome-local-overrides/) to explore the example without the inconvience of having to run your own web server.
+It is recommended you use [Google Chrome's 'Local Overrides' located in the Developer Tools panel](https://www.trysmudford.com/blog/chrome-local-overrides/) to explore the example without the inconvenience of having to run your own web server.
#### Pre-built `prebid.js`
diff --git a/modules/adlooxRtdProvider.js b/modules/adlooxRtdProvider.js
index 8862ac8ac47..c2037429185 100644
--- a/modules/adlooxRtdProvider.js
+++ b/modules/adlooxRtdProvider.js
@@ -6,11 +6,13 @@
* @module modules/adlooxRtdProvider
* @requires module:modules/realTimeData
* @requires module:modules/adlooxAnalyticsAdapter
+ * @optional module:modules/intersectionRtdProvider
*/
/* eslint standard/no-callback-literal: "off" */
/* eslint prebid/validate-imports: "off" */
+import {auctionManager} from '../src/auctionManager.js';
import {command as analyticsCommand, COMMAND} from './adlooxAnalyticsAdapter.js';
import {submodule} from '../src/hook.js';
import {ajax} from '../src/ajax.js';
@@ -18,142 +20,31 @@ import {getGlobal} from '../src/prebidGlobal.js';
import {getRefererInfo} from '../src/refererDetection.js';
import {
_each,
+ _map,
+ buildUrl,
deepAccess,
+ deepClone,
deepSetValue,
- getAdUnitSizes,
getGptSlotInfoForAdUnitCode,
isArray,
isBoolean,
isInteger,
isPlainObject,
- isStr,
logError,
logInfo,
logWarn,
- mergeDeep
+ mergeDeep,
+ parseUrl,
+ safeJSONParse
} from '../src/utils.js';
-import {includes} from '../src/polyfill.js';
const MODULE_NAME = 'adloox';
const MODULE = `${MODULE_NAME}RtdProvider`;
const API_ORIGIN = 'https://p.adlooxtracking.com';
const SEGMENT_HISTORIC = { 'a': 'aud', 'd': 'dis', 'v': 'vid' };
-const SEGMENT_HISTORIC_VALUES = Object.keys(SEGMENT_HISTORIC).map(k => SEGMENT_HISTORIC[k]);
-const ADSERVER_TARGETING_PREFIX = 'adl_';
-
-const CREATIVE_WIDTH_MIN = 20;
-const CREATIVE_HEIGHT_MIN = 20;
-const CREATIVE_AREA_MIN = CREATIVE_WIDTH_MIN * CREATIVE_HEIGHT_MIN;
-// try to avoid using IntersectionObserver as it has unbounded (observed multi-second) latency
-let intersectionObserver = window == top ? false : undefined;
-const intersectionObserverElements = [];
-// .map/.findIndex are safe here as they are only used for intersectionObserver
-function atf(adUnit, cb) {
- analyticsCommand(COMMAND.TOSELECTOR, { bid: { adUnitCode: adUnit.code } }, function(selector) {
- const element = document.querySelector(selector);
- if (!element) return cb(null);
-
- if (window.getComputedStyle(element)['display'] == 'none') return cb(NaN);
-
- try {
- // short circuit for cross-origin
- if (intersectionObserver) throw false;
-
- // Google's advice is to collapse slots on no fill but
- // we have to cater to clients that grow slots on fill
- const rect = (function(rect) {
- const sizes = getAdUnitSizes(adUnit);
-
- if (sizes.length == 0) return false;
- // interstitial (0x0, 1x1)
- if (sizes.length == 1 && (sizes[0][0] * sizes[0][1]) <= 1) return true;
- // try to catch premium slots (coord=0,0) as they will likely bounce into view
- if (rect.top <= -window.pageYOffset && rect.left <= -window.pageXOffset && rect.top == rect.bottom) return true;
-
- // pick the smallest creative size as many publishers will just leave the element unbounded in the vertical
- let width = Infinity;
- let height = Infinity;
- for (let i = 0; i < sizes.length; i++) {
- const area = sizes[i][0] * sizes[i][1];
- if (area < CREATIVE_AREA_MIN) continue;
- if (area < (width * height)) {
- width = sizes[i][0];
- height = sizes[i][1];
- }
- }
- // we also scale the smallest size to the size of the slot as publishers resize units depending on viewport
- const scale = Math.min(1, (rect.right - rect.left) / width);
-
- return {
- left: rect.left,
- right: rect.left + Math.max(CREATIVE_WIDTH_MIN, scale * width),
- top: rect.top,
- bottom: rect.top + Math.max(CREATIVE_HEIGHT_MIN, scale * height)
- };
- })(element.getBoundingClientRect());
-
- if (rect === false) return cb(NaN);
- if (rect === true) return cb(1);
-
- const W = rect.right - rect.left;
- const H = rect.bottom - rect.top;
-
- if (W * H < CREATIVE_AREA_MIN) return cb(NaN);
-
- let el;
- let win = window;
- while (1) {
- // https://stackoverflow.com/a/8876069
- const vw = Math.max(win.document.documentElement.clientWidth || 0, win.innerWidth || 0);
- const vh = Math.max(win.document.documentElement.clientHeight || 0, win.innerHeight || 0);
-
- // cut to viewport
- rect.left = Math.min(Math.max(rect.left, 0), vw);
- rect.right = Math.min(Math.max(rect.right, 0), vw);
- rect.top = Math.min(Math.max(rect.top, 0), vh);
- rect.bottom = Math.min(Math.max(rect.bottom, 0), vh);
-
- if (win == top) return cb(((rect.right - rect.left) * (rect.bottom - rect.top)) / (W * H));
- el = win.frameElement;
- if (!el) throw false; // cross-origin
- win = win.parent;
-
- // transpose to frame element
- const frameElementRect = el.getBoundingClientRect();
- rect.left += frameElementRect.left;
- rect.right = Math.min(rect.right + frameElementRect.left, frameElementRect.right);
- rect.top += frameElementRect.top;
- rect.bottom = Math.min(rect.bottom + frameElementRect.top, frameElementRect.bottom);
- }
- } catch (_) {
- if (intersectionObserver === undefined) {
- try {
- intersectionObserver = new IntersectionObserver(function(entries) {
- entries.forEach(entry => {
- const ratio = entry.intersectionRect.width * entry.intersectionRect.height < CREATIVE_AREA_MIN ? NaN : entry.intersectionRatio;
- const idx = intersectionObserverElements.findIndex(x => x.element == entry.target);
- intersectionObserverElements[idx].cb.forEach(cb => cb(ratio));
- intersectionObserverElements.splice(idx, 1);
- intersectionObserver.unobserve(entry.target);
- });
- });
- } catch (_) {
- intersectionObserver = false;
- }
- }
- if (!intersectionObserver) return cb(null);
- const idx = intersectionObserverElements.findIndex(x => x.element == element);
- if (idx == -1) {
- intersectionObserverElements.push({ element, cb: [ cb ] });
- intersectionObserver.observe(element);
- } else {
- intersectionObserverElements[idx].cb.push(cb);
- }
- }
- });
-}
+const ADSERVER_TARGETING_PREFIX = 'adl';
function init(config, userConsent) {
logInfo(MODULE, 'init', config, userConsent);
@@ -167,10 +58,6 @@ function init(config, userConsent) {
logError(MODULE, 'invalid params');
return false;
}
- if (!(config.params.api_origin === undefined || isStr(config.params.api_origin))) {
- logError(MODULE, 'invalid api_origin params value');
- return false;
- }
if (!(config.params.imps === undefined || (isInteger(config.params.imps) && config.params.imps > 0))) {
logError(MODULE, 'invalid imps params value');
return false;
@@ -213,193 +100,110 @@ function init(config, userConsent) {
}
function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) {
- // gptPreAuction runs *after* RTD so pbadslot may not be populated... (╯°□°)╯ ┻━┻
- const adUnits = (reqBidsConfigObj.adUnits || getGlobal().adUnits).map(adUnit => {
- return {
- gpid: deepAccess(adUnit, 'ortb2Imp.ext.gpid') || deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot') || getGptSlotInfoForAdUnitCode(adUnit.code).gptSlot || adUnit.code,
- unit: adUnit
- };
- }).filter(adUnit => !!adUnit.gpid);
-
- let response = {};
- function setSegments() {
- function val(v, k) {
- if (!((SEGMENT_HISTORIC[k] || k == 'atf') && v >= 0)) return v;
- return config.params.thresholds.filter(t => t <= v);
- }
-
- const ortb2 = reqBidsConfigObj.ortb2Fragments?.global || {};
- const dataSite = deepAccess(ortb2, 'site.ext.data') || {};
- const dataUser = deepAccess(ortb2, 'user.ext.data') || {};
-
- _each(response, (v0, k0) => {
- if (k0 == '_') return;
- const k = SEGMENT_HISTORIC[k0] || k0;
- const v = val(v0, k0);
- deepSetValue(k == k0 ? dataUser : dataSite, `${MODULE_NAME}_rtd.${k}`, v);
- });
- deepSetValue(dataSite, `${MODULE_NAME}_rtd.ok`, true);
+ const adUnits0 = reqBidsConfigObj.adUnits || getGlobal().adUnits;
+ // adUnits must be ordered according to adUnitCodes for stable 's' param usage and handling the response below
+ const adUnits = reqBidsConfigObj.adUnitCodes.map(code => adUnits0.find(unit => unit.code == code));
+
+ // buildUrl creates PHP style multi-parameters and includes undefined... (╯°□°)╯ ┻━┻
+ const url = buildUrl(mergeDeep(parseUrl(`${API_ORIGIN}/q`), { search: {
+ 'v': `pbjs-${getGlobal().version}`,
+ 'c': config.params.clientid,
+ 'p': config.params.platformid,
+ 't': config.params.tagid,
+ 'imp': config.params.imps,
+ 'fc_ip': config.params.freqcap_ip,
+ 'fc_ipua': config.params.freqcap_ipua,
+ 'pn': (getRefererInfo().page || '').substr(0, 300).split(/[?#]/)[0],
+ 's': _map(adUnits, function(unit) {
+ // gptPreAuction runs *after* RTD so pbadslot may not be populated... (╯°□°)╯ ┻━┻
+ const gpid = deepAccess(unit, 'ortb2Imp.ext.gpid') ||
+ deepAccess(unit, 'ortb2Imp.ext.data.pbadslot') ||
+ getGptSlotInfoForAdUnitCode(unit.code).gptSlot ||
+ unit.code;
+ const ref = [ gpid ];
+ if (!config.params.slotinpath) ref.push(unit.code);
+ return ref.join('\t');
+ })
+ } })).replace(/\[\]|[^?&]+=undefined/g, '').replace(/([?&])&+/g, '$1');
+
+ ajax(url,
+ function(responseText, q) {
+ function val(v, k) {
+ if (!(SEGMENT_HISTORIC[k] && v >= 0)) return v;
+ return config.params.thresholds.filter(t => t <= v);
+ }
- deepSetValue(ortb2, 'site.ext.data', dataSite);
- deepSetValue(ortb2, 'user.ext.data', dataUser);
- deepSetValue(reqBidsConfigObj, 'ortb2Fragments.global', ortb2);
+ const response = safeJSONParse(responseText);
+ if (!response) {
+ logError(MODULE, 'unexpected response');
+ return callback();
+ }
- adUnits.forEach((adUnit, i) => {
- _each(response['_'][i], (v0, k0) => {
+ const { site: ortb2site, user: ortb2user } = reqBidsConfigObj.ortb2Fragments.global;
+ _each(response, function(v0, k0) {
+ if (k0 == '_') return;
const k = SEGMENT_HISTORIC[k0] || k0;
const v = val(v0, k0);
- deepSetValue(adUnit.unit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd.${k}`, v);
+ deepSetValue(k == k0 ? ortb2user : ortb2site, `ext.data.${MODULE_NAME}_rtd.${k}`, v);
});
- });
- };
-
- // mergeDeep does not handle merging deep arrays... (╯°□°)╯ ┻━┻
- function mergeDeep(target, ...sources) {
- function emptyValue(v) {
- if (isPlainObject(v)) {
- return {};
- } else if (isArray(v)) {
- return [];
- } else {
- return undefined;
- }
- }
- if (!sources.length) return target;
- const source = sources.shift();
-
- if (isPlainObject(target) && isPlainObject(source)) {
- Object.keys(source).forEach(key => {
- if (!(key in target)) target[key] = emptyValue(source[key]);
- target[key] = target[key] !== undefined ? mergeDeep(target[key], source[key]) : source[key];
- });
- } else if (isArray(target) && isArray(source)) {
- source.forEach((v, i) => {
- if (!(i in target)) target[i] = emptyValue(v);
- target[i] = target[i] !== undefined ? mergeDeep(target[i], v) : v;
+ _each(response._, function(segments, i) {
+ _each(segments, function(v0, k0) {
+ const k = SEGMENT_HISTORIC[k0] || k0;
+ const v = val(v0, k0);
+ deepSetValue(adUnits[i], `ortb2Imp.ext.data.${MODULE_NAME}_rtd.${k}`, v);
+ });
});
- } else {
- target = source;
- }
- return mergeDeep(target, ...sources);
- }
+ deepSetValue(ortb2site, `ext.data.${MODULE_NAME}_rtd.ok`, true);
- let semaphore = 1;
- function semaphoreInc(inc) {
- if (semaphore == 0) return;
- semaphore += inc;
- if (semaphore == 0) {
- setSegments()
callback();
}
- }
-
- const refererInfo = getRefererInfo();
- const args = [
- [ 'v', `pbjs-${getGlobal().version}` ],
- [ 'c', config.params.clientid ],
- [ 'p', config.params.platformid ],
- [ 't', config.params.tagid ],
- [ 'imp', config.params.imps ],
- [ 'fc_ip', config.params.freqcap_ip ],
- [ 'fc_ipua', config.params.freqcap_ipua ],
- [ 'pn', (refererInfo.page || '').substr(0, 300).split(/[?#]/)[0] ]
- ];
-
- if (!adUnits.length) {
- logWarn(MODULE, 'no suitable adUnits (missing pbadslot?)');
- }
- const atfQueue = [];
- adUnits.map((adUnit, i) => {
- const ref = [ adUnit.gpid ];
- if (!config.params.slotinpath) ref.push(adUnit.unit.code);
- args.push(['s', ref.join('\t')]);
-
- semaphoreInc(1);
- atfQueue.push(function() {
- atf(adUnit.unit, function(x) {
- let viewable = document.visibilityState === undefined || document.visibilityState == 'visible';
- try { viewable = viewable && top.document.hasFocus() } catch (_) {}
- logInfo(MODULE, `atf code=${adUnit.unit.code} has area=${x}, viewable=${viewable}`);
- const atfList = []; atfList[i] = { atf: parseInt(x * 100) };
- response = mergeDeep(response, { _: atfList });
- semaphoreInc(-1);
- });
- });
- });
- function atfCb() {
- atfQueue.forEach(x => x());
- }
- if (document.readyState == 'loading') {
- document.addEventListener('DOMContentLoaded', atfCb, false);
- } else {
- atfCb();
- }
-
- analyticsCommand(COMMAND.URL, {
- url: (config.params.api_origin || API_ORIGIN) + '/q?',
- args: args
- }, function(url) {
- ajax(url, {
- success: function(responseText, q) {
- try {
- if (q.getResponseHeader('content-type') == 'application/json') {
- response = mergeDeep(response, JSON.parse(responseText));
- } else {
- throw false;
- }
- } catch (_) {
- logError(MODULE, 'unexpected response');
- }
- semaphoreInc(-1);
- },
- error: function(statusText, q) {
- logError(MODULE, 'request failed');
- semaphoreInc(-1);
- }
- });
- });
+ );
}
function getTargetingData(adUnitArray, config, userConsent, auction) {
- function targetingNormalise(v) {
+ function val(v) {
if (isArray(v) && v.length == 0) return undefined;
if (isBoolean(v)) v = ~~v;
if (!v) return undefined; // empty string and zero
return v;
}
- const ortb2 = auction.getFPD().global || {};
- const dataSite = deepAccess(ortb2, `site.ext.data.${MODULE_NAME}_rtd`) || {};
- if (!dataSite.ok) return {};
+ const { site: ortb2site, user: ortb2user } = auctionManager.index.getAuction(auction).getFPD().global;
- const dataUser = deepAccess(ortb2, `user.ext.data.${MODULE_NAME}_rtd`) || {};
- return getGlobal().adUnits.filter(adUnit => includes(adUnitArray, adUnit.code)).reduce((a, adUnit) => {
- a[adUnit.code] = {};
+ const ortb2base = {};
+ _each(deepAccess(mergeDeep(ortb2site, ortb2user), `ext.data.${MODULE_NAME}_rtd`), function(v0, k) {
+ const v = val(v0);
+ if (v) ortb2base[`${ADSERVER_TARGETING_PREFIX}_${k}`] = v;
+ });
- _each(dataSite, (v0, k) => {
- if (includes(SEGMENT_HISTORIC_VALUES, k)) return; // ignore site average viewability
- const v = targetingNormalise(v0);
- if (v) a[adUnit.code][ADSERVER_TARGETING_PREFIX + k] = v;
- });
+ const targeting = {};
+ _each(auction.adUnits.filter(unit => adUnitArray.includes(unit.code)), function(unit) {
+ targeting[unit.code] = deepClone(ortb2base);
- const adUnitSegments = deepAccess(adUnit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd`, {});
- _each(Object.assign({}, dataUser, adUnitSegments), (v0, k) => {
- const v = targetingNormalise(v0);
- if (v) a[adUnit.code][ADSERVER_TARGETING_PREFIX + k] = v;
+ const ortb2imp = deepAccess(unit, `ortb2Imp.ext.data.${MODULE_NAME}_rtd`);
+ _each(ortb2imp, function(v0, k) {
+ const v = val(v0);
+ if (v) targeting[unit.code][`${ADSERVER_TARGETING_PREFIX}_${k}`] = v;
});
- return a;
- }, {});
+ // ATF results shamelessly exfiltrated from intersectionRtdProvider
+ const bid = unit.bids.find(bid => !!bid.intersection);
+ if (bid) {
+ const v = val(config.params.thresholds.filter(t => t <= (bid.intersection.intersectionRatio * 100)));
+ if (v) targeting[unit.code][`${ADSERVER_TARGETING_PREFIX}_atf`] = v;
+ }
+ });
+
+ return targeting;
}
export const subModuleObj = {
name: MODULE_NAME,
init,
getBidRequestData,
- getTargetingData,
- atf // used by adlooxRtdProvider_spec.js
+ getTargetingData
};
submodule('realTimeData', subModuleObj);
diff --git a/modules/adlooxRtdProvider.md b/modules/adlooxRtdProvider.md
index 466f8ed1ba2..9d6a20a01a7 100644
--- a/modules/adlooxRtdProvider.md
+++ b/modules/adlooxRtdProvider.md
@@ -19,12 +19,7 @@ This provider fetches segments and populates the [First Party Data](https://docs
* AdUnit segments are placed into `AdUnit.ortb2Imp.ext.data.adloox_rtd`:
* **`{dis,vid,aud}`:** an list of integers describing the likelihood the AdUnit will be visible
* **`atf`:** an list of integers describing the percentage of pixels visible at auction
- * measured only once at pre-auction
- * usable when the publisher uses the strategy of collapsing ad slots on no-fill
- * using the reverse strategy, growing ad slots on fill, invalidates the measurement the position of all content (including the slots) changes post-auction
- * works best when your page loads your ad slots have their actual size rendered (ie. not zero height)
- * uses the smallest ad unit (above a threshold area of 20x20) supplied by the [publisher to Prebid.js](https://docs.prebid.org/dev-docs/examples/basic-example.html) and measures viewability as if that size to be used
- * when used in cross-origin (unfriendly) IFRAME environments the ad slot is directly measured as is (ignoring publisher provided sizes) due to limitations in using [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)
+ * measured at pre-auction time using the [Intersection Module](https://docs.prebid.org/dev-docs/modules/intersectionRtdProvider.html); if not enabled then this measurement is not available
**N.B.** this provider does not offer or utilise any user orientated data
@@ -57,8 +52,13 @@ To use this, you *must* also integrate the [Adloox Analytics Adapter](./adlooxAn
realTimeData: {
auctionDelay: 100, // see below for guidance
dataProviders: [
+ {
+ name: 'intersection',
+ waitForIt: true
+ },
{
name: 'adloox',
+ waitForIt: true,
params: { // optional, defaults shown
thresholds: [ 50, 60, 70, 80, 90 ],
slotinpath: false
diff --git a/modules/alkimiBidAdapter.js b/modules/alkimiBidAdapter.js
index fe5a050f436..a96b245d786 100644
--- a/modules/alkimiBidAdapter.js
+++ b/modules/alkimiBidAdapter.js
@@ -20,18 +20,20 @@ export const spec = {
let bidIds = [];
let eids;
validBidRequests.forEach(bidRequest => {
- let sizes = prepareSizes(bidRequest.sizes)
+ let formatType = getFormatType(bidRequest)
+ let alkimiSizes = prepareAlkimiSizes(bidRequest.sizes)
if (bidRequest.userIdAsEids) {
eids = eids || bidRequest.userIdAsEids
}
+
bids.push({
token: bidRequest.params.token,
pos: bidRequest.params.pos,
- bidFloor: bidRequest.params.bidFloor,
- width: sizes[0].width,
- height: sizes[0].height,
- impMediaType: getFormatType(bidRequest),
+ bidFloor: getBidFloor(bidRequest, formatType),
+ width: alkimiSizes[0].width,
+ height: alkimiSizes[0].height,
+ impMediaType: formatType,
adUnitCode: bidRequest.adUnitCode
})
bidIds.push(bidRequest.bidId)
@@ -128,10 +130,25 @@ export const spec = {
}
}
-function prepareSizes(sizes) {
+function prepareAlkimiSizes(sizes) {
return sizes && sizes.map(size => ({ width: size[0], height: size[1] }));
}
+function prepareBidFloorSize(sizes) {
+ return sizes && sizes.length === 1 ? sizes[0] : '*';
+}
+
+function getBidFloor(bidRequest, formatType) {
+ if (typeof bidRequest.getFloor === 'function') {
+ const bidFloorSize = prepareBidFloorSize(bidRequest.sizes)
+ const floor = bidRequest.getFloor({ currency: 'USD', mediaType: formatType.toLowerCase(), size: bidFloorSize });
+ if (floor && !isNaN(floor.floor) && (floor.currency === 'USD')) {
+ return floor.floor;
+ }
+ }
+ return bidRequest.params.bidFloor;
+}
+
const getFormatType = bidRequest => {
if (deepAccess(bidRequest, 'mediaTypes.banner')) return 'Banner'
if (deepAccess(bidRequest, 'mediaTypes.video')) return 'Video'
diff --git a/modules/aolBidAdapter.js b/modules/aolBidAdapter.js
index d38c373ff1f..6b471ac6de2 100644
--- a/modules/aolBidAdapter.js
+++ b/modules/aolBidAdapter.js
@@ -159,6 +159,13 @@ export const spec = {
if (bidderRequest) {
consentData.gdpr = bidderRequest.gdprConsent;
consentData.uspConsent = bidderRequest.uspConsent;
+ consentData.gppConsent = bidderRequest.gppConsent;
+ if (!consentData.gppConsent && bidderRequest.ortb2?.regs?.gpp) {
+ consentData.gppConsent = {
+ gppString: bidderRequest.ortb2.regs.gpp,
+ applicableSections: bidderRequest.ortb2.regs.gpp_sid
+ }
+ }
}
return bids.map(bid => {
@@ -373,6 +380,11 @@ export const spec = {
params.us_privacy = consentData.uspConsent;
}
+ if (consentData.gppConsent && consentData.gppConsent.gppString) {
+ params.gpp = consentData.gppConsent.gppString;
+ params.gpp_sid = consentData.gppConsent.applicableSections;
+ }
+
return params;
},
parsePixelItems(pixels) {
diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js
index 919831b8515..b64334b0d77 100644
--- a/modules/appnexusBidAdapter.js
+++ b/modules/appnexusBidAdapter.js
@@ -625,9 +625,8 @@ function newBid(serverBid, rtbBid, bidderRequest) {
}
};
- // WE DON'T FULLY SUPPORT THIS ATM - future spot for adomain code; creating a stub for 5.0 compliance
if (rtbBid.adomain) {
- bid.meta = Object.assign({}, bid.meta, { advertiserDomains: [] });
+ bid.meta = Object.assign({}, bid.meta, { advertiserDomains: [rtbBid.adomain] });
}
if (rtbBid.advertiser_id) {
@@ -731,6 +730,7 @@ function newBid(serverBid, rtbBid, bidderRequest) {
displayUrl: nativeAd.displayurl,
clickTrackers: nativeAd.link.click_trackers,
impressionTrackers: nativeAd.impression_trackers,
+ video: nativeAd.video,
javascriptTrackers: jsTrackers
};
if (nativeAd.main_img) {
diff --git a/modules/appushBidAdapter.js b/modules/appushBidAdapter.js
new file mode 100644
index 00000000000..1ad8fe27e42
--- /dev/null
+++ b/modules/appushBidAdapter.js
@@ -0,0 +1,188 @@
+import { isFn, deepAccess, logMessage, logError } from '../src/utils.js';
+import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
+
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
+import { config } from '../src/config.js';
+
+const BIDDER_CODE = 'appush';
+const AD_URL = 'https://hb.appush.com/pbjs';
+
+function isBidResponseValid(bid) {
+ if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
+ return false;
+ }
+
+ switch (bid.mediaType) {
+ case BANNER:
+ return Boolean(bid.width && bid.height && bid.ad);
+ case VIDEO:
+ return Boolean(bid.vastUrl || bid.vastXml);
+ case NATIVE:
+ return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length);
+ default:
+ return false;
+ }
+}
+
+function getPlacementReqData(bid) {
+ const { params, bidId, mediaTypes } = bid;
+ const schain = bid.schain || {};
+ const { placementId, endpointId } = params;
+ const bidfloor = getBidFloor(bid);
+
+ const placement = {
+ bidId,
+ schain,
+ bidfloor
+ };
+
+ if (placementId) {
+ placement.placementId = placementId;
+ placement.type = 'publisher';
+ } else if (endpointId) {
+ placement.endpointId = endpointId;
+ placement.type = 'network';
+ }
+
+ if (mediaTypes && mediaTypes[BANNER]) {
+ placement.adFormat = BANNER;
+ placement.sizes = mediaTypes[BANNER].sizes;
+ } else if (mediaTypes && mediaTypes[VIDEO]) {
+ placement.adFormat = VIDEO;
+ placement.playerSize = mediaTypes[VIDEO].playerSize;
+ placement.minduration = mediaTypes[VIDEO].minduration;
+ placement.maxduration = mediaTypes[VIDEO].maxduration;
+ placement.mimes = mediaTypes[VIDEO].mimes;
+ placement.protocols = mediaTypes[VIDEO].protocols;
+ placement.startdelay = mediaTypes[VIDEO].startdelay;
+ placement.placement = mediaTypes[VIDEO].placement;
+ placement.skip = mediaTypes[VIDEO].skip;
+ placement.skipafter = mediaTypes[VIDEO].skipafter;
+ placement.minbitrate = mediaTypes[VIDEO].minbitrate;
+ placement.maxbitrate = mediaTypes[VIDEO].maxbitrate;
+ placement.delivery = mediaTypes[VIDEO].delivery;
+ placement.playbackmethod = mediaTypes[VIDEO].playbackmethod;
+ placement.api = mediaTypes[VIDEO].api;
+ placement.linearity = mediaTypes[VIDEO].linearity;
+ } else if (mediaTypes && mediaTypes[NATIVE]) {
+ placement.native = mediaTypes[NATIVE];
+ placement.adFormat = NATIVE;
+ }
+
+ return placement;
+}
+
+function getBidFloor(bid) {
+ if (!isFn(bid.getFloor)) {
+ return deepAccess(bid, 'params.bidfloor', 0);
+ }
+
+ try {
+ const bidFloor = bid.getFloor({
+ currency: 'USD',
+ mediaType: '*',
+ size: '*',
+ });
+ return bidFloor.floor;
+ } catch (err) {
+ logError(err);
+ return 0;
+ }
+}
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER, VIDEO, NATIVE],
+
+ isBidRequestValid: (bid = {}) => {
+ const { params, bidId, mediaTypes } = bid;
+ let valid = Boolean(bidId && params && (params.placementId || params.endpointId));
+
+ if (mediaTypes && mediaTypes[BANNER]) {
+ valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes);
+ } else if (mediaTypes && mediaTypes[VIDEO]) {
+ valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize);
+ } else if (mediaTypes && mediaTypes[NATIVE]) {
+ valid = valid && Boolean(mediaTypes[NATIVE]);
+ } else {
+ valid = false;
+ }
+ return valid;
+ },
+
+ buildRequests: (validBidRequests = [], bidderRequest = {}) => {
+ // convert Native ORTB definition to old-style prebid native definition
+ validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
+
+ let deviceWidth = 0;
+ let deviceHeight = 0;
+
+ let winLocation;
+ try {
+ const winTop = window.top;
+ deviceWidth = winTop.screen.width;
+ deviceHeight = winTop.screen.height;
+ winLocation = winTop.location;
+ } catch (e) {
+ logMessage(e);
+ winLocation = window.location;
+ }
+
+ const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page;
+ let refferLocation;
+ try {
+ refferLocation = refferUrl && new URL(refferUrl);
+ } catch (e) {
+ logMessage(e);
+ }
+ // TODO: does the fallback make sense here?
+ let location = refferLocation || winLocation;
+ const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : '';
+ const host = location.host;
+ const page = location.pathname;
+ const secure = location.protocol === 'https:' ? 1 : 0;
+ const placements = [];
+ const request = {
+ deviceWidth,
+ deviceHeight,
+ language,
+ secure,
+ host,
+ page,
+ placements,
+ coppa: config.getConfig('coppa') === true ? 1 : 0,
+ ccpa: bidderRequest.uspConsent || undefined,
+ gdpr: bidderRequest.gdprConsent || undefined,
+ tmax: config.getConfig('bidderTimeout')
+ };
+
+ const len = validBidRequests.length;
+ for (let i = 0; i < len; i++) {
+ const bid = validBidRequests[i];
+ placements.push(getPlacementReqData(bid));
+ }
+
+ return {
+ method: 'POST',
+ url: AD_URL,
+ data: request
+ };
+ },
+
+ interpretResponse: (serverResponse) => {
+ let response = [];
+ for (let i = 0; i < serverResponse.body.length; i++) {
+ let resItem = serverResponse.body[i];
+ if (isBidResponseValid(resItem)) {
+ const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : [];
+ resItem.meta = { ...resItem.meta, advertiserDomains };
+
+ response.push(resItem);
+ }
+ }
+ return response;
+ }
+};
+
+registerBidder(spec);
diff --git a/modules/appushBidAdapter.md b/modules/appushBidAdapter.md
new file mode 100644
index 00000000000..7c04c3a6425
--- /dev/null
+++ b/modules/appushBidAdapter.md
@@ -0,0 +1,79 @@
+# Overview
+
+```
+Module Name: Appush Bidder Adapter
+Module Type: Appush Bidder Adapter
+Maintainer: support@appush.com
+```
+
+# Description
+
+Connects to Appush exchange for bids.
+Appush bid adapter supports Banner, Video (instream and outstream) and Native.
+
+# Test Parameters
+```
+ var adUnits = [
+ // Will return static test banner
+ {
+ code: 'adunit1',
+ mediaTypes: {
+ banner: {
+ sizes: [ [300, 250], [320, 50] ],
+ }
+ },
+ bids: [
+ {
+ bidder: 'appush',
+ params: {
+ placementId: 'testBanner',
+ }
+ }
+ ]
+ },
+ {
+ code: 'addunit2',
+ mediaTypes: {
+ video: {
+ playerSize: [ [640, 480] ],
+ context: 'instream',
+ minduration: 5,
+ maxduration: 60,
+ }
+ },
+ bids: [
+ {
+ bidder: 'appush',
+ params: {
+ placementId: 'testVideo',
+ }
+ }
+ ]
+ },
+ {
+ code: 'addunit3',
+ mediaTypes: {
+ native: {
+ title: {
+ required: true
+ },
+ body: {
+ required: true
+ },
+ icon: {
+ required: true,
+ size: [64, 64]
+ }
+ }
+ },
+ bids: [
+ {
+ bidder: 'appush',
+ params: {
+ placementId: 'testNative',
+ }
+ }
+ ]
+ }
+ ];
+```
\ No newline at end of file
diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js
index 24ef8ad0af5..38c9c00b0ed 100644
--- a/modules/connectIdSystem.js
+++ b/modules/connectIdSystem.js
@@ -66,6 +66,11 @@ export const connectIdSubmodule = {
us_privacy: consentData && consentData.uspConsent ? consentData.uspConsent : ''
};
+ if (connectIdSubmodule.isUnderGPPJurisdiction(consentData)) {
+ data.gpp = consentData.gppConsent.gppString;
+ data.gpp_sid = encodeURIComponent(consentData.gppConsent.applicableSections.join(','));
+ }
+
INPUT_PARAM_KEYS.forEach(key => {
if (typeof params[key] != 'undefined') {
data[key] = params[key];
@@ -98,7 +103,7 @@ export const connectIdSubmodule = {
},
/**
- * Utility function that returns a boolean flag indicating if the opporunity
+ * Utility function that returns a boolean flag indicating if the opportunity
* is subject to GDPR
* @returns {Boolean}
*/
@@ -106,6 +111,15 @@ export const connectIdSubmodule = {
return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies);
},
+ /**
+ * Utility function that returns a boolean flag indicating if the opportunity
+ * is subject to GPP jurisdiction.
+ * @returns {Boolean}
+ */
+ isUnderGPPJurisdiction(consentData) {
+ return !!(consentData && consentData.gppConsent && consentData.gppConsent.gppString);
+ },
+
/**
* Utility function that returns a boolean flag indicating if the user
* has opeted out via the Yahoo easy-opt-out mechanism.
diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js
index ef2e57c553f..7b684efab3c 100644
--- a/modules/feedadBidAdapter.js
+++ b/modules/feedadBidAdapter.js
@@ -7,7 +7,7 @@ import {ajax} from '../src/ajax.js';
* Version of the FeedAd bid adapter
* @type {string}
*/
-const VERSION = '1.0.4';
+const VERSION = '1.0.5';
/**
* @typedef {object} FeedAdApiBidRequest
@@ -16,7 +16,8 @@ const VERSION = '1.0.4';
* @property {number} ad_type
* @property {string} client_token
* @property {string} placement_id
- * @property {string} sdk_version
+ * @property {string} prebid_adapter_version
+ * @property {string} prebid_sdk_version
* @property {boolean} app_hybrid
*
* @property {string} [app_bundle_id]
@@ -181,7 +182,8 @@ function createApiBidRParams(request) {
ad_type: 0,
client_token: request.params.clientToken,
placement_id: request.params.placementId,
- sdk_version: `prebid_${VERSION}`,
+ prebid_adapter_version: VERSION,
+ prebid_sdk_version: '$prebid.version$',
app_hybrid: false,
});
}
@@ -207,7 +209,6 @@ function buildRequests(validBidRequests, bidderRequest) {
})
});
data.bids.forEach(bid => BID_METADATA[bid.bidId] = {
- // TODO: is 'page' the right value here?
referer: data.refererInfo.page,
transactionId: bid.transactionId
});
@@ -266,7 +267,8 @@ function createTrackingParams(data, klass) {
prebid_bid_id: bidId,
prebid_transaction_id: transactionId,
referer,
- sdk_version: VERSION
+ prebid_adapter_version: VERSION,
+ prebid_sdk_version: '$prebid.version$',
};
}
diff --git a/modules/jwplayerVideoProvider.js b/modules/jwplayerVideoProvider.js
index 379d8063c42..6264522ad83 100644
--- a/modules/jwplayerVideoProvider.js
+++ b/modules/jwplayerVideoProvider.js
@@ -47,19 +47,26 @@ export function JWPlayerProvider(config, jwplayer_, adState_, timeState_, callba
function init() {
if (!jwplayer) {
- triggerSetupFailure(-1); // TODO: come up with code for player absent
+ triggerSetupFailure(-1); // TODO: come up with error code schema- player is absent
return;
}
playerVersion = jwplayer.version;
if (playerVersion < minimumSupportedPlayerVersion) {
- triggerSetupFailure(-2); // TODO: come up with code for version not supported
+ triggerSetupFailure(-2); // TODO: come up with error code schema - version not supported
+ return;
+ }
+
+ if (!document.getElementById(divId)) {
+ triggerSetupFailure(-3); // TODO: come up with error code schema - missing div id
return;
}
player = jwplayer(divId);
- if (player.getState() === undefined) {
+ if (!player || !player.getState) {
+ triggerSetupFailure(-4); // TODO: come up with error code schema - factory function failure
+ } else if (player.getState() === undefined) {
setupPlayer(playerConfig);
} else {
const payload = getSetupCompletePayload();
diff --git a/modules/lotamePanoramaIdSystem.js b/modules/lotamePanoramaIdSystem.js
index 19bb975858e..883c931824b 100644
--- a/modules/lotamePanoramaIdSystem.js
+++ b/modules/lotamePanoramaIdSystem.js
@@ -29,7 +29,7 @@ const DAY_MS = 60 * 60 * 24 * 1000;
const MISSING_CORE_CONSENT = 111;
const GVLID = 95;
const ID_HOST = 'id.crwdcntrl.net';
-const SAFARI_ID_HOST = 'c.ltmsphrcl.net';
+const ID_HOST_COOKIELESS = 'c.ltmsphrcl.net';
export const storage = getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME});
let cookieDomain;
@@ -255,7 +255,7 @@ export const lotamePanoramaIdSubmodule = {
const getRequestHost = function() {
if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
- return SAFARI_ID_HOST;
+ return ID_HOST_COOKIELESS;
}
return ID_HOST;
}
diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js
index ff4ca77aac2..96738f586c1 100644
--- a/modules/nexx360BidAdapter.js
+++ b/modules/nexx360BidAdapter.js
@@ -79,9 +79,6 @@ function createImpObject(bid) {
}
}
};
- if (bid.params.customParams) {
- utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams);
- }
enrichImp(imp, bid, floor);
return imp;
}
@@ -154,9 +151,6 @@ function getFloor(bid, mediaType) {
}
function enrichImp(imp, bid, floor) {
- if (bid.params.customParams) {
- utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams);
- }
if (floor > 0) {
imp.bidfloor = floor;
imp.bidfloorcur = 'USD';
@@ -251,6 +245,7 @@ function interpretResponse(response, req) {
let bids = [];
respBody.seatbid.forEach(seatbid => {
+ const ssp = seatbid.seat;
bids = [...bids, ...seatbid.bid.map(bid => {
const response = {
requestId: bid.impid,
@@ -264,7 +259,10 @@ function interpretResponse(response, req) {
ttl: 120,
bidderCode: allowAlternateBidderCodes ? `n360-${bid.ssp}` : 'nexx360',
mediaType: bid.type === 'banner' ? 'banner' : 'video',
- meta: { advertiserDomains: bid.adomain },
+ meta: {
+ advertiserDomains: bid.adomain,
+ demandSource: ssp,
+ },
};
// if (bid.dealid) response.dealid = bid.dealid;
diff --git a/modules/orbitsoftBidAdapter.js b/modules/orbitsoftBidAdapter.js
new file mode 100644
index 00000000000..d72a8719bd8
--- /dev/null
+++ b/modules/orbitsoftBidAdapter.js
@@ -0,0 +1,150 @@
+import * as utils from '../src/utils.js';
+import {registerBidder} from '../src/adapters/bidderFactory.js';
+import {config} from '../src/config.js';
+
+const BIDDER_CODE = 'orbitsoft';
+let styleParamsMap = {
+ 'title.family': 'f1', // headerFont
+ 'title.size': 'fs1', // headerFontSize
+ 'title.weight': 'w1', // headerWeight
+ 'title.style': 's1', // headerStyle
+ 'title.color': 'c3', // headerColor
+ 'description.family': 'f2', // descriptionFont
+ 'description.size': 'fs2', // descriptionFontSize
+ 'description.weight': 'w2', // descriptionWeight
+ 'description.style': 's2', // descriptionStyle
+ 'description.color': 'c4', // descriptionColor
+ 'url.family': 'f3', // urlFont
+ 'url.size': 'fs3', // urlFontSize
+ 'url.weight': 'w3', // urlWeight
+ 'url.style': 's3', // urlStyle
+ 'url.color': 'c5', // urlColor
+ 'colors.background': 'c2', // borderColor
+ 'colors.border': 'c1', // borderColor
+ 'colors.link': 'c6', // lnkColor
+};
+export const spec = {
+ code: BIDDER_CODE,
+ aliases: ['oas', '152media'], // short code and customer aliases
+ isBidRequestValid: function (bid) {
+ switch (true) {
+ case !('params' in bid):
+ utils.logError(bid.bidder + ': No required params');
+ return false;
+ case !(bid.params.placementId):
+ utils.logError(bid.bidder + ': No required param placementId');
+ return false;
+ case !(bid.params.requestUrl):
+ utils.logError(bid.bidder + ': No required param requestUrl');
+ return false;
+ }
+ return true;
+ },
+ buildRequests: function (validBidRequests) {
+ let bidRequest;
+ let serverRequests = [];
+ for (let i = 0; i < validBidRequests.length; i++) {
+ bidRequest = validBidRequests[i];
+ let bidRequestParams = bidRequest.params;
+ let placementId = utils.getBidIdParameter('placementId', bidRequestParams);
+ let requestUrl = utils.getBidIdParameter('requestUrl', bidRequestParams);
+ let referrer = utils.getBidIdParameter('ref', bidRequestParams);
+ let location = utils.getBidIdParameter('loc', bidRequestParams);
+ // Append location & referrer
+ if (location === '') {
+ location = utils.getWindowLocation();
+ }
+ if (referrer === '' && bidRequest && bidRequest.refererInfo) {
+ referrer = bidRequest.refererInfo.referer;
+ }
+
+ // Styles params
+ let stylesParams = utils.getBidIdParameter('style', bidRequestParams);
+ let stylesParamsArray = {};
+ for (let currentValue in stylesParams) {
+ if (stylesParams.hasOwnProperty(currentValue)) {
+ let currentStyle = stylesParams[currentValue];
+ for (let field in currentStyle) {
+ if (currentStyle.hasOwnProperty(field)) {
+ let styleField = styleParamsMap[currentValue + '.' + field];
+ if (typeof styleField !== 'undefined') {
+ stylesParamsArray[styleField] = currentStyle[field];
+ }
+ }
+ }
+ }
+ }
+ // Custom params
+ let customParams = utils.getBidIdParameter('customParams', bidRequestParams);
+ let customParamsArray = {};
+ for (let customField in customParams) {
+ if (customParams.hasOwnProperty(customField)) {
+ customParamsArray['c.' + customField] = customParams[customField];
+ }
+ }
+
+ // Sizes params (not supports by server, for future features)
+ let sizesParams = bidRequest.sizes;
+ let parsedSizes = utils.parseSizesInput(sizesParams);
+ let requestData = Object.assign({
+ 'scid': placementId,
+ 'callback_uid': utils.generateUUID(),
+ 'loc': location,
+ 'ref': referrer,
+ 'size': parsedSizes
+ }, stylesParamsArray, customParamsArray);
+
+ serverRequests.push({
+ method: 'POST',
+ url: requestUrl,
+ data: requestData,
+ options: {withCredentials: false},
+ bidRequest: bidRequest
+ });
+ }
+ return serverRequests;
+ },
+ interpretResponse: function (serverResponse, request) {
+ let bidResponses = [];
+ if (!serverResponse || serverResponse.error) {
+ utils.logError(BIDDER_CODE + ': Server response error');
+ return bidResponses;
+ }
+
+ const serverBody = serverResponse.body;
+ if (!serverBody) {
+ utils.logError(BIDDER_CODE + ': Empty bid response');
+ return bidResponses;
+ }
+
+ const CPM = serverBody.cpm;
+ const WIDTH = serverBody.width;
+ const HEIGHT = serverBody.height;
+ const CREATIVE = serverBody.content_url;
+ const CALLBACK_UID = serverBody.callback_uid;
+ const TIME_TO_LIVE = config.getConfig('_bidderTimeout');
+ const REFERER = utils.getWindowTop();
+ let bidRequest = request.bidRequest;
+ if (CPM > 0 && WIDTH > 0 && HEIGHT > 0) {
+ let bidResponse = {
+ requestId: bidRequest.bidId,
+ cpm: CPM,
+ width: WIDTH,
+ height: HEIGHT,
+ creativeId: CALLBACK_UID,
+ ttl: TIME_TO_LIVE,
+ referrer: REFERER,
+ currency: 'USD',
+ netRevenue: true,
+ adUrl: CREATIVE,
+ meta: {
+ advertiserDomains: serverBody.adomain ? serverBody.adomain : []
+ }
+ };
+ bidResponses.push(bidResponse);
+ }
+
+ return bidResponses;
+ }
+};
+registerBidder(spec);
diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js
index d62834cfcfc..c64080f3308 100644
--- a/modules/permutiveRtdProvider.js
+++ b/modules/permutiveRtdProvider.js
@@ -243,7 +243,7 @@ function getCustomBidderFn (moduleConfig, bidder) {
*/
function getDefaultBidderFn (bidder) {
const isPStandardTargetingEnabled = (data, acEnabled) => {
- return (acEnabled && data.ac && data.ac.length) || (data.ssp && data.ssp.cohorts.length)
+ return (acEnabled && data.ac && data.ac.length) || (data.ssp && data.ssp.cohorts && data.ssp.cohorts.length)
}
const pStandardTargeting = (data, acEnabled) => {
const ac = (acEnabled) ? (data.ac ?? []) : []
diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js
index 1a4f903789b..d5abb89437b 100644
--- a/modules/seedtagBidAdapter.js
+++ b/modules/seedtagBidAdapter.js
@@ -260,6 +260,18 @@ export const spec = {
payload.coppa = coppa;
}
+ if (bidderRequest.gppConsent) {
+ payload.gppConsent = {
+ gppString: bidderRequest.gppConsent.gppString,
+ applicableSections: bidderRequest.gppConsent.applicableSections
+ }
+ } else if (bidderRequest.ortb2?.regs?.gpp) {
+ payload.gppConsent = {
+ gppString: bidderRequest.ortb2.regs.gpp,
+ applicableSections: bidderRequest.ortb2.regs.gpp_sid
+ }
+ }
+
const payloadString = JSON.stringify(payload);
return {
method: 'POST',
diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js
index 452aaafb09b..bfc664180a3 100644
--- a/modules/smartxBidAdapter.js
+++ b/modules/smartxBidAdapter.js
@@ -76,6 +76,7 @@ export const spec = {
const bidfloor = getBidFloor(bid) || 0;
const bidfloorcur = getBidIdParameter('bidfloorcur', bid.params) || 'EUR';
const siteId = getBidIdParameter('siteId', bid.params);
+ const sitekey = getBidIdParameter('sitekey', bid.params);
const domain = getBidIdParameter('domain', bid.params);
const cat = getBidIdParameter('cat', bid.params) || [''];
let pubcid = null;
@@ -191,6 +192,11 @@ export const spec = {
}
}
+ // Add sitekey if available
+ if (sitekey) {
+ requestPayload.site.content.ext.sitekey = sitekey;
+ }
+
// Add common id if available
if (pubcid) {
userExt.fpc = pubcid;
diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js
index 85adfc31ca5..2e10a8d8951 100644
--- a/modules/taboolaBidAdapter.js
+++ b/modules/taboolaBidAdapter.js
@@ -3,7 +3,7 @@
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
-import {getWindowSelf, replaceAuctionPrice} from '../src/utils.js'
+import {deepAccess, getWindowSelf, replaceAuctionPrice} from '../src/utils.js'
import {getStorageManager} from '../src/storageManager.js';
import { ajax } from '../src/ajax.js';
@@ -123,7 +123,6 @@ export const spec = {
id: bidderRequest.auctionId,
imp: imps,
site,
- pageType: ortb2?.ext?.data?.pageType || ortb2?.ext?.data?.section || bidRequest.params.pageType,
device,
source: {fd: 1},
tmax: bidderRequest.timeout,
@@ -131,7 +130,10 @@ export const spec = {
badv: ortb2.badv || bidRequest.params.badv || [],
wlang: ortb2.wlang || bidRequest.params.wlang || [],
user,
- regs
+ regs,
+ ext: {
+ pageType: ortb2?.ext?.data?.pageType || ortb2?.ext?.data?.section || bidRequest.params.pageType
+ }
};
const url = [END_POINT_URL, publisherId].join('/');
@@ -212,9 +214,8 @@ function getImps(validBidRequests) {
const {tagId, position} = bid.params;
const imp = {
id: id + 1,
- banner: getBanners(bid),
- tagid: tagId,
- position: position
+ banner: getBanners(bid, position),
+ tagid: tagId
}
if (typeof bid.getFloor === 'function') {
const floorInfo = bid.getFloor({
@@ -231,12 +232,18 @@ function getImps(validBidRequests) {
imp.bidfloor = bidfloor;
imp.bidfloorcur = bidfloorcur;
}
+ imp['ext'] = {
+ gpid: deepAccess(bid, 'ortb2Imp.ext.gpid')
+ }
return imp;
});
}
-function getBanners(bid) {
- return getSizes(bid.sizes);
+function getBanners(bid, pos) {
+ return {
+ ...getSizes(bid.sizes),
+ pos: pos
+ }
}
function getSizes(sizes) {
diff --git a/modules/yahoosspBidAdapter.js b/modules/yahoosspBidAdapter.js
index 8f9ede4fccc..9dd635a990f 100644
--- a/modules/yahoosspBidAdapter.js
+++ b/modules/yahoosspBidAdapter.js
@@ -279,6 +279,11 @@ function generateOpenRtbObject(bidderRequest, bid) {
outBoundBidRequest.site.id = bid.params.dcn;
};
+ if (bidderRequest.ortb2?.regs?.gpp) {
+ outBoundBidRequest.regs.ext.gpp = bidderRequest.ortb2.regs.gpp;
+ outBoundBidRequest.regs.ext.gpp_sid = bidderRequest.ortb2.regs.gpp_sid
+ };
+
if (bidderRequest.ortb2) {
outBoundBidRequest = appendFirstPartyData(outBoundBidRequest, bid);
};
diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js
index 6e4f6644140..cadeb9c1300 100644
--- a/modules/yieldlabBidAdapter.js
+++ b/modules/yieldlabBidAdapter.js
@@ -1,17 +1,17 @@
-import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js'
-import { registerBidder } from '../src/adapters/bidderFactory.js'
-import { find } from '../src/polyfill.js'
-import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'
-import { Renderer } from '../src/Renderer.js'
+import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js';
+import { registerBidder } from '../src/adapters/bidderFactory.js';
+import { find } from '../src/polyfill.js';
+import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
+import { Renderer } from '../src/Renderer.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
-const ENDPOINT = 'https://ad.yieldlab.net'
-const BIDDER_CODE = 'yieldlab'
-const BID_RESPONSE_TTL_SEC = 300
-const CURRENCY_CODE = 'EUR'
-const OUTSTREAMPLAYER_URL = 'https://ad.adition.com/dynamic.ad?a=o193092&ma_loadEvent=ma-start-event'
-const GVLID = 70
-const DIMENSION_SIGN = 'x'
+const ENDPOINT = 'https://ad.yieldlab.net';
+const BIDDER_CODE = 'yieldlab';
+const BID_RESPONSE_TTL_SEC = 300;
+const CURRENCY_CODE = 'EUR';
+const OUTSTREAMPLAYER_URL = 'https://ad.adition.com/dynamic.ad?a=o193092&ma_loadEvent=ma-start-event';
+const GVLID = 70;
+const DIMENSION_SIGN = 'x';
export const spec = {
code: BIDDER_CODE,
@@ -22,11 +22,11 @@ export const spec = {
* @param {object} bid
* @returns {boolean}
*/
- isBidRequestValid: function (bid) {
+ isBidRequestValid(bid) {
if (bid && bid.params && bid.params.adslotId && bid.params.supplyId) {
- return true
+ return true;
}
- return false
+ return false;
},
/**
@@ -35,85 +35,85 @@ export const spec = {
* @param [bidderRequest]
* @returns {ServerRequest|ServerRequest[]}
*/
- buildRequests: function (validBidRequests, bidderRequest) {
+ buildRequests(validBidRequests, bidderRequest) {
// convert Native ORTB definition to old-style prebid native definition
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
- const adslotIds = []
+ const adslotIds = [];
const adslotSizes = [];
const adslotFloors = [];
- const timestamp = Date.now()
+ const timestamp = Date.now();
const query = {
ts: timestamp,
- json: true
- }
+ json: true,
+ };
_each(validBidRequests, function (bid) {
- adslotIds.push(bid.params.adslotId)
- const sizes = extractSizes(bid)
+ adslotIds.push(bid.params.adslotId);
+ const sizes = extractSizes(bid);
if (sizes.length > 0) {
- adslotSizes.push(bid.params.adslotId + ':' + sizes.join('|'))
+ adslotSizes.push(bid.params.adslotId + ':' + sizes.join('|'));
}
if (bid.params.extId) {
query.id = bid.params.extId;
}
if (bid.params.targeting) {
- query.t = createTargetingString(bid.params.targeting)
+ query.t = createTargetingString(bid.params.targeting);
}
if (bid.userIdAsEids && Array.isArray(bid.userIdAsEids)) {
- query.ids = createUserIdString(bid.userIdAsEids)
- query.atypes = createUserIdAtypesString(bid.userIdAsEids)
+ query.ids = createUserIdString(bid.userIdAsEids);
+ query.atypes = createUserIdAtypesString(bid.userIdAsEids);
}
if (bid.params.customParams && isPlainObject(bid.params.customParams)) {
for (const prop in bid.params.customParams) {
- query[prop] = bid.params.customParams[prop]
+ query[prop] = bid.params.customParams[prop];
}
}
if (bid.schain && isPlainObject(bid.schain) && Array.isArray(bid.schain.nodes)) {
- query.schain = createSchainString(bid.schain)
+ query.schain = createSchainString(bid.schain);
}
- const iabContent = getContentObject(bid)
+ const iabContent = getContentObject(bid);
if (iabContent) {
- query.iab_content = createIabContentString(iabContent)
+ query.iab_content = createIabContentString(iabContent);
}
- const floor = getBidFloor(bid, sizes)
+ const floor = getBidFloor(bid, sizes);
if (floor) {
adslotFloors.push(bid.params.adslotId + ':' + floor);
}
- })
+ });
if (bidderRequest) {
if (bidderRequest.refererInfo && bidderRequest.refererInfo.page) {
// TODO: is 'page' the right value here?
- query.pubref = bidderRequest.refererInfo.page
+ query.pubref = bidderRequest.refererInfo.page;
}
if (bidderRequest.gdprConsent) {
- query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
+ query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true;
if (query.gdpr) {
- query.consent = bidderRequest.gdprConsent.consentString
+ query.consent = bidderRequest.gdprConsent.consentString;
}
}
}
- const adslots = adslotIds.join(',')
+ const adslots = adslotIds.join(',');
if (adslotSizes.length > 0) {
- query.sizes = adslotSizes.join(',')
+ query.sizes = adslotSizes.join(',');
}
if (adslotFloors.length > 0) {
- query.floor = adslotFloors.join(',')
+ query.floor = adslotFloors.join(',');
}
- const queryString = createQueryString(query)
+ const queryString = createQueryString(query);
return {
method: 'GET',
url: `${ENDPOINT}/yp/${adslots}?${queryString}`,
validBidRequests: validBidRequests,
- queryParams: query
- }
+ queryParams: query,
+ };
},
/**
@@ -122,29 +122,29 @@ export const spec = {
* @param {BidRequest} originalBidRequest
* @returns {Bid[]}
*/
- interpretResponse: function (serverResponse, originalBidRequest) {
- const bidResponses = []
- const timestamp = Date.now()
- const reqParams = originalBidRequest.queryParams
+ interpretResponse(serverResponse, originalBidRequest) {
+ const bidResponses = [];
+ const timestamp = Date.now();
+ const reqParams = originalBidRequest.queryParams;
originalBidRequest.validBidRequests.forEach(function (bidRequest) {
if (!serverResponse.body) {
- return
+ return;
}
const matchedBid = find(serverResponse.body, function (bidResponse) {
- return bidRequest.params.adslotId == bidResponse.id
- })
+ return bidRequest.params.adslotId == bidResponse.id;
+ });
if (matchedBid) {
- const adUnitSize = bidRequest.sizes.length === 2 && !isArray(bidRequest.sizes[0]) ? bidRequest.sizes : bidRequest.sizes[0]
- const adSize = bidRequest.params.adSize !== undefined ? parseSize(bidRequest.params.adSize) : (matchedBid.adsize !== undefined) ? parseSize(matchedBid.adsize) : adUnitSize
- const extId = bidRequest.params.extId !== undefined ? '&id=' + bidRequest.params.extId : ''
- const adType = matchedBid.adtype !== undefined ? matchedBid.adtype : ''
- const gdprApplies = reqParams.gdpr ? '&gdpr=' + reqParams.gdpr : ''
- const gdprConsent = reqParams.consent ? '&consent=' + reqParams.consent : ''
- const pvId = matchedBid.pvid !== undefined ? '&pvid=' + matchedBid.pvid : ''
- const iabContent = reqParams.iab_content ? '&iab_content=' + reqParams.iab_content : ''
+ const adUnitSize = bidRequest.sizes.length === 2 && !isArray(bidRequest.sizes[0]) ? bidRequest.sizes : bidRequest.sizes[0];
+ const adSize = bidRequest.params.adSize !== undefined ? parseSize(bidRequest.params.adSize) : (matchedBid.adsize !== undefined) ? parseSize(matchedBid.adsize) : adUnitSize;
+ const extId = bidRequest.params.extId !== undefined ? '&id=' + bidRequest.params.extId : '';
+ const adType = matchedBid.adtype !== undefined ? matchedBid.adtype : '';
+ const gdprApplies = reqParams.gdpr ? '&gdpr=' + reqParams.gdpr : '';
+ const gdprConsent = reqParams.consent ? '&consent=' + reqParams.consent : '';
+ const pvId = matchedBid.pvid !== undefined ? '&pvid=' + matchedBid.pvid : '';
+ const iabContent = reqParams.iab_content ? '&iab_content=' + reqParams.iab_content : '';
const bidResponse = {
requestId: bidRequest.bidId,
@@ -159,38 +159,38 @@ export const spec = {
referrer: '',
ad: ``,
meta: {
- advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a'
- }
- }
+ advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a',
+ },
+ };
if (isVideo(bidRequest, adType)) {
- const playersize = getPlayerSize(bidRequest)
+ const playersize = getPlayerSize(bidRequest);
if (playersize) {
- bidResponse.width = playersize[0]
- bidResponse.height = playersize[1]
+ bidResponse.width = playersize[0];
+ bidResponse.height = playersize[1];
}
- bidResponse.mediaType = VIDEO
- bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}`
+ bidResponse.mediaType = VIDEO;
+ bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}`;
if (isOutstream(bidRequest)) {
const renderer = Renderer.install({
id: bidRequest.bidId,
url: OUTSTREAMPLAYER_URL,
- loaded: false
- })
- renderer.setRender(outstreamRender)
- bidResponse.renderer = renderer
+ loaded: false,
+ });
+ renderer.setRender(outstreamRender);
+ bidResponse.renderer = renderer;
}
}
if (isNative(bidRequest, adType)) {
// there may be publishers still rely on it
- const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`
- bidResponse.adUrl = url
- bidResponse.mediaType = NATIVE
- const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2)
+ const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`;
+ bidResponse.adUrl = url;
+ bidResponse.mediaType = NATIVE;
+ const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2);
const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : { url: '', w: 0, h: 0 };
- const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1)
- const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3)
+ const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1);
+ const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3);
bidResponse.native = {
title: nativeTitleAsset ? nativeTitleAsset.title.text : '',
body: nativeBodyAsset ? nativeBodyAsset.data.value : '',
@@ -204,10 +204,10 @@ export const spec = {
};
}
- bidResponses.push(bidResponse)
+ bidResponses.push(bidResponse);
}
- })
- return bidResponses
+ });
+ return bidResponses;
},
/**
@@ -219,13 +219,13 @@ export const spec = {
* @param {string} uspConsent Is the US Privacy Consent string.
* @return {UserSync[]} The user syncs which should be dropped.
*/
- getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) {
+ getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
const syncs = [];
if (syncOptions.iframeEnabled) {
const params = [];
params.push(`ts=${timestamp()}`);
- params.push(`type=h`)
+ params.push(`type=h`);
if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) {
params.push(`gdpr=${Number(gdprConsent.gdprApplies)}`);
}
@@ -234,12 +234,12 @@ export const spec = {
}
syncs.push({
type: 'iframe',
- url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}`
+ url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}`,
});
}
return syncs;
- }
+ },
};
/**
@@ -249,7 +249,7 @@ export const spec = {
* @returns {Boolean}
*/
function isVideo(format, adtype) {
- return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video'
+ return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video';
}
/**
@@ -259,7 +259,7 @@ function isVideo(format, adtype) {
* @returns {Boolean}
*/
function isNative(format, adtype) {
- return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native'
+ return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native';
}
/**
@@ -268,8 +268,8 @@ function isNative(format, adtype) {
* @returns {Boolean}
*/
function isOutstream(format) {
- const context = deepAccess(format, 'mediaTypes.video.context')
- return (context === 'outstream')
+ const context = deepAccess(format, 'mediaTypes.video.context');
+ return (context === 'outstream');
}
/**
@@ -278,30 +278,30 @@ function isOutstream(format) {
* @returns {Array}
*/
function getPlayerSize(format) {
- const playerSize = deepAccess(format, 'mediaTypes.video.playerSize')
- return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize
+ const playerSize = deepAccess(format, 'mediaTypes.video.playerSize');
+ return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize;
}
/**
- * Expands a 'WxH' string as a 2-element [W, H] array
+ * Expands a 'WxH' string to a 2-element [W, H] array
* @param {String} size
* @returns {Array}
*/
function parseSize(size) {
- return size.split(DIMENSION_SIGN).map(Number)
+ return size.split(DIMENSION_SIGN).map(Number);
}
/**
* Creates a string out of an array of eids with source and uid
- * @param {Array} eids
+ * @param {Array.<{source: String, uids: Array.<{id: String, atype: Number, ext: Object}>}>} eids
* @returns {String}
*/
function createUserIdString(eids) {
- const str = []
+ const str = [];
for (let i = 0; i < eids.length; i++) {
- str.push(eids[i].source + ':' + eids[i].uids[0].id)
+ str.push(eids[i].source + ':' + eids[i].uids[0].id);
}
- return str.join(',')
+ return str.join(',');
}
/**
@@ -325,18 +325,18 @@ function createUserIdAtypesString(eids) {
* @returns {String}
*/
function createQueryString(obj) {
- const str = []
+ const str = [];
for (const p in obj) {
if (obj.hasOwnProperty(p)) {
- const val = obj[p]
+ const val = obj[p];
if (p !== 'schain' && p !== 'iab_content') {
- str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val))
+ str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val));
} else {
- str.push(p + '=' + val)
+ str.push(p + '=' + val);
}
}
}
- return str.join('&')
+ return str.join('&');
}
/**
@@ -345,15 +345,15 @@ function createQueryString(obj) {
* @returns {String}
*/
function createTargetingString(obj) {
- const str = []
+ const str = [];
for (const p in obj) {
if (obj.hasOwnProperty(p)) {
- const key = p
- const val = obj[p]
- str.push(key + '=' + val)
+ const key = p;
+ const val = obj[p];
+ str.push(key + '=' + val);
}
}
- return str.join('&')
+ return str.join('&');
}
/**
@@ -362,13 +362,13 @@ function createTargetingString(obj) {
* @returns {String}
*/
function createSchainString(schain) {
- const ver = schain.ver || ''
- const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : ''
- const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext']
+ const ver = schain.ver || '';
+ const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : '';
+ const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext'];
const nodesString = schain.nodes.reduce((acc, node) => {
- return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}`
- }, '')
- return `${ver},${complete}${nodesString}`
+ return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}`;
+ }, '');
+ return `${ver},${complete}${nodesString}`;
}
/**
@@ -380,15 +380,15 @@ function createSchainString(schain) {
*/
function getContentObject(bid) {
if (bid.params.iabContent && isPlainObject(bid.params.iabContent)) {
- return bid.params.iabContent
+ return bid.params.iabContent;
}
const globalContent = deepAccess(bid, 'ortb2.site') ? deepAccess(bid, 'ortb2.site.content')
- : deepAccess(bid, 'ortb2.app.content')
+ : deepAccess(bid, 'ortb2.app.content');
if (globalContent && isPlainObject(globalContent)) {
- return globalContent
+ return globalContent;
}
- return undefined
+ return undefined;
}
/**
@@ -401,15 +401,15 @@ function getContentObject(bid) {
* @returns {String}
*/
function createIabContentString(iabContent) {
- const arrKeys = ['keywords', 'cat']
- const str = []
+ const arrKeys = ['keywords', 'cat'];
+ const str = [];
const transformObjToParam = (obj = {}, extraKey = '') => {
for (const key in obj) {
if ((arrKeys.indexOf(key) !== -1 && Array.isArray(obj[key]))) {
// Array of defined keyword which have to be joined into one value from "key: [value1, value2, value3]" to "key:value1|value2|value3"
- str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|')))
+ str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|')));
} else if (typeof obj[key] !== 'object') {
- str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key])))
+ str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key])));
} else {
// Object has to be further flattened
transformObjToParam(obj[key], ''.concat(extraKey, key, '.'));
@@ -417,7 +417,7 @@ function createIabContentString(iabContent) {
}
return str.join(',');
};
- return encodeURIComponent(transformObjToParam(iabContent))
+ return encodeURIComponent(transformObjToParam(iabContent));
}
/**
@@ -426,7 +426,7 @@ function createIabContentString(iabContent) {
* @returns {String}
*/
function encodeURIComponentWithBangIncluded(str) {
- return encodeURIComponent(str).replace(/!/g, '%21')
+ return encodeURIComponent(str).replace(/!/g, '%21');
}
/**
@@ -435,11 +435,11 @@ function encodeURIComponentWithBangIncluded(str) {
*/
function outstreamRender(bid) {
bid.renderer.push(() => {
- window.ma_width = bid.width
- window.ma_height = bid.height
- window.ma_vastUrl = bid.vastUrl
- window.ma_container = bid.adUnitCode
- window.document.dispatchEvent(new Event('ma-start-event'))
+ window.ma_width = bid.width;
+ window.ma_height = bid.height;
+ window.ma_vastUrl = bid.vastUrl;
+ window.ma_container = bid.adUnitCode;
+ window.document.dispatchEvent(new Event('ma-start-event'));
});
}
@@ -450,33 +450,33 @@ function outstreamRender(bid) {
* @returns {string[]}
*/
function extractSizes(bid) {
- const { mediaTypes } = bid // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples
- const sizes = []
+ const { mediaTypes } = bid; // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples
+ const sizes = [];
if (isPlainObject(mediaTypes)) {
- const { [BANNER]: bannerType } = mediaTypes
+ const { [BANNER]: bannerType } = mediaTypes;
// only applies for multi size Adslots -> BANNER
if (bannerType && isArray(bannerType.sizes)) {
if (isArray(bannerType.sizes[0])) { // multiple sizes given
- sizes.push(bannerType.sizes)
+ sizes.push(bannerType.sizes);
} else { // just one size provided as array -> wrap to uniformly flatten later
- sizes.push([bannerType.sizes])
+ sizes.push([bannerType.sizes]);
}
}
// The bid top level field `sizes` is deprecated and should not be used anymore. Keeping it for compatibility.
} else if (isArray(bid.sizes)) {
if (isArray(bid.sizes[0])) {
- sizes.push(bid.sizes)
+ sizes.push(bid.sizes);
} else {
- sizes.push([bid.sizes])
+ sizes.push([bid.sizes]);
}
}
/** @type {Set} */
- const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height))
+ const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height));
- return Array.from(deduplicatedSizeStrings)
+ return Array.from(deduplicatedSizeStrings);
}
/**
@@ -497,7 +497,7 @@ function getBidFloor(bid, sizes) {
const floor = bid.getFloor({
currency: CURRENCY_CODE,
mediaType: mediaType !== undefined && spec.supportedMediaTypes.includes(mediaType) ? mediaType : '*',
- size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN)
+ size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN),
});
if (floor.currency === CURRENCY_CODE) {
return (floor.floor * 100).toFixed(0);
@@ -505,4 +505,4 @@ function getBidFloor(bid, sizes) {
return undefined;
}
-registerBidder(spec)
+registerBidder(spec);
diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js
index 64ab8a87eea..5a0f302ab34 100644
--- a/modules/yieldmoBidAdapter.js
+++ b/modules/yieldmoBidAdapter.js
@@ -385,7 +385,7 @@ function openRtbRequest(bidRequests, bidderRequest) {
at: 1,
imp: bidRequests.map(bidRequest => openRtbImpression(bidRequest)),
site: openRtbSite(bidRequests[0], bidderRequest),
- device: openRtbDevice(bidRequests[0]),
+ device: deepAccess(bidderRequest, 'ortb2.device'),
badv: bidRequests[0].params.badv || [],
bcat: deepAccess(bidderRequest, 'bcat') || bidRequests[0].params.bcat || [],
ext: {
@@ -507,17 +507,6 @@ function openRtbSite(bidRequest, bidderRequest) {
return result;
}
-/**
- * @return Object OpenRTB's 'device' object
- */
-function openRtbDevice(bidRequest) {
- const deviceObj = {
- ua: navigator.userAgent,
- language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage),
- };
- return deviceObj;
-}
-
/**
* Updates openRtbRequest with GDPR info from bidderRequest, if present.
* @param {Object} openRtbRequest OpenRTB's request to update.
diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js
index 436d481c4a1..8abdc621922 100644
--- a/test/spec/modules/adagioBidAdapter_spec.js
+++ b/test/spec/modules/adagioBidAdapter_spec.js
@@ -149,10 +149,8 @@ describe('Adagio bid adapter', () => {
site: {
ext: {
data: {
- environment: 'desktop',
pagetype: 'abc',
- category: ['cat1', 'cat2', 'cat3'],
- subcategory: []
+ category: ['cat1', 'cat2', 'cat3']
}
}
}
@@ -167,17 +165,11 @@ describe('Adagio bid adapter', () => {
return utils.deepAccess(config, key);
});
- setExtraParam(bid, 'environment');
- expect(bid.params.environment).to.equal('desktop');
-
setExtraParam(bid, 'pagetype')
expect(bid.params.pagetype).to.equal('article');
setExtraParam(bid, 'category');
expect(bid.params.category).to.equal('cat1'); // Only the first value is kept
-
- setExtraParam(bid, 'subcategory');
- expect(bid.params.subcategory).to.be.undefined;
});
it('should use the adUnit param unit if defined', function() {
@@ -784,8 +776,6 @@ describe('Adagio bid adapter', () => {
adUnitElementId: 'gpt-adunit-code',
pagetype: 'ARTICLE',
category: 'NEWS',
- subcategory: 'SPORT',
- environment: 'desktop',
supportIObs: true
},
adUnitCode: 'adunit-code',
@@ -833,8 +823,6 @@ describe('Adagio bid adapter', () => {
site: 'SITE-NAME',
pagetype: 'ARTICLE',
category: 'NEWS',
- subcategory: 'SPORT',
- environment: 'desktop',
aDomain: ['advertiser.com'],
mediaType: 'banner',
meta: {
@@ -868,8 +856,6 @@ describe('Adagio bid adapter', () => {
site: 'SITE-NAME',
pagetype: 'ARTICLE',
category: 'NEWS',
- subcategory: 'SPORT',
- environment: 'desktop',
aDomain: ['advertiser.com'],
mediaType: 'banner',
meta: {
@@ -1392,19 +1378,6 @@ describe('Adagio bid adapter', () => {
});
describe.skip('optional params auto detection', function() {
- it('should auto detect environment', function() {
- const getDeviceStub = sandbox.stub(_features, 'getDevice');
-
- getDeviceStub.returns(5);
- expect(adagio.autoDetectEnvironment()).to.eq('tablet');
-
- getDeviceStub.returns(4);
- expect(adagio.autoDetectEnvironment()).to.eq('mobile');
-
- getDeviceStub.returns(2);
- expect(adagio.autoDetectEnvironment()).to.eq('desktop');
- });
-
it('should auto detect adUnitElementId when GPT is used', function() {
sandbox.stub(utils, 'getGptSlotInfoForAdUnitCode').withArgs('banner').returns({divId: 'gpt-banner'});
expect(adagio.autoDetectAdUnitElementId('banner')).to.eq('gpt-banner');
diff --git a/test/spec/modules/adlooxRtdProvider_spec.js b/test/spec/modules/adlooxRtdProvider_spec.js
index 236e053e58c..5b99789981f 100644
--- a/test/spec/modules/adlooxRtdProvider_spec.js
+++ b/test/spec/modules/adlooxRtdProvider_spec.js
@@ -1,5 +1,6 @@
import adapterManager from 'src/adapterManager.js';
import analyticsAdapter from 'modules/adlooxAnalyticsAdapter.js';
+import {auctionManager} from 'src/auctionManager.js';
import { config as _config } from 'src/config.js';
import { expect } from 'chai';
import * as events from 'src/events.js';
@@ -75,14 +76,6 @@ describe('Adloox RTD Provider', function () {
done();
});
- it('should reject non-string config.params.api_origin', function (done) {
- const ret = rtdProvider.init({ params: { api_origin: null } });
-
- expect(ret).is.false;
-
- done();
- });
-
it('should reject less than one config.params.imps', function (done) {
const ret = rtdProvider.init({ params: { imps: 0 } });
@@ -147,31 +140,37 @@ describe('Adloox RTD Provider', function () {
});
let server = null;
- let __config = null, CONFIG = null;
- let getConfigStub, setConfigStub;
+ let CONFIG = null;
beforeEach(function () {
server = sinon.createFakeServer();
- __config = {};
CONFIG = utils.deepClone(config);
- getConfigStub = sinon.stub(_config, 'getConfig').callsFake(function (path) {
- return utils.deepAccess(__config, path);
- });
- setConfigStub = sinon.stub(_config, 'setConfig').callsFake(function (obj) {
- utils.mergeDeep(__config, obj);
- });
});
afterEach(function () {
- setConfigStub.restore();
- getConfigStub.restore();
- getConfigStub = setConfigStub = undefined;
CONFIG = null;
- __config = null;
server.restore();
server = null;
});
it('should fetch segments', function (done) {
- const req = {};
+ const req = {
+ adUnitCodes: [ adUnit.code ],
+ ortb2Fragments: {
+ global: {
+ site: {
+ ext: {
+ data: {
+ }
+ }
+ },
+ user: {
+ ext: {
+ data: {
+ }
+ }
+ }
+ }
+ }
+ };
const adUnitWithSegments = utils.deepClone(adUnit);
const getGlobalStub = sinon.stub(prebidGlobal, 'getGlobal').returns({
adUnits: [ adUnitWithSegments ]
@@ -201,119 +200,28 @@ describe('Adloox RTD Provider', function () {
});
it('should set ad server targeting', function (done) {
- utils.deepSetValue(__config, 'ortb2.site.ext.data.adloox_rtd.ok', true);
-
const adUnitWithSegments = utils.deepClone(adUnit);
utils.deepSetValue(adUnitWithSegments, 'ortb2Imp.ext.data.adloox_rtd.dis', [ 50, 60 ]);
const getGlobalStub = sinon.stub(prebidGlobal, 'getGlobal').returns({
adUnits: [ adUnitWithSegments ]
});
- const targetingData = rtdProvider.getTargetingData([ adUnitWithSegments.code ], CONFIG, null, {
- getFPD: () => ({
- global: __config.ortb2
- })
+ const auction = { adUnits: [ adUnitWithSegments ] };
+ const getAuctionStub = sinon.stub(auctionManager.index, 'getAuction').returns({
+ adUnits: [ adUnitWithSegments ],
+ getFPD: () => { return { global: { site: { ext: { data: { adloox_rtd: { ok: true } } } } } } }
});
+
+ const targetingData = rtdProvider.getTargetingData([ adUnitWithSegments.code ], CONFIG, null, auction);
expect(Object.keys(targetingData).length).is.equal(1);
expect(Object.keys(targetingData[adUnit.code]).length).is.equal(2);
expect(targetingData[adUnit.code].adl_ok).is.equal(1);
expect(targetingData[adUnit.code].adl_dis.length).is.equal(2);
+ getAuctionStub.restore();
getGlobalStub.restore();
done();
});
});
-
- describe('measure atf', function () {
- const adUnitCopy = utils.deepClone(adUnit);
-
- const ratio = 0.38;
- const [ [width, height] ] = utils.getAdUnitSizes(adUnitCopy);
-
- before(function () {
- adapterManager.enableAnalytics({
- provider: analyticsAdapterName,
- options: analyticsOptions
- });
- expect(analyticsAdapter.context).is.not.null;
- });
-
- after(function () {
- analyticsAdapter.disableAnalytics();
- expect(analyticsAdapter.context).is.null;
- });
-
- it(`should return ${ratio} for same-origin`, function (done) {
- const el = document.createElement('div');
- el.setAttribute('id', adUnitCopy.code);
-
- const offset = height * ratio;
- const elStub = sinon.stub(el, 'getBoundingClientRect').returns({
- top: 0 - (height - offset),
- bottom: height - offset,
- left: 0,
- right: width
- });
-
- const querySelectorStub = sinon.stub(document, 'querySelector');
- querySelectorStub.withArgs(`#${adUnitCopy.code}`).returns(el);
-
- rtdProvider.atf(adUnitCopy, function(x) {
- expect(x).is.equal(ratio);
-
- querySelectorStub.restore();
- elStub.restore();
-
- done();
- });
- });
-
- ('IntersectionObserver' in window ? it : it.skip)(`should return ${ratio} for cross-origin`, function (done) {
- const frameElementStub = sinon.stub(window, 'frameElement').value(null);
-
- const el = document.createElement('div');
- el.setAttribute('id', adUnitCopy.code);
-
- const elStub = sinon.stub(el, 'getBoundingClientRect').returns({
- top: 0,
- bottom: height,
- left: 0,
- right: width
- });
-
- const querySelectorStub = sinon.stub(document, 'querySelector');
- querySelectorStub.withArgs(`#${adUnitCopy.code}`).returns(el);
-
- let intersectionObserverStubFn = null;
- const intersectionObserverStub = sinon.stub(window, 'IntersectionObserver').callsFake((fn) => {
- intersectionObserverStubFn = fn;
- return {
- observe: (element) => {
- expect(element).is.equal(el);
-
- intersectionObserverStubFn([{
- target: element,
- intersectionRect: { width, height },
- intersectionRatio: ratio
- }]);
- },
- unobserve: (element) => {
- expect(element).is.equal(el);
- }
- }
- });
-
- rtdProvider.atf(adUnitCopy, function(x) {
- expect(x).is.equal(ratio);
-
- intersectionObserverStub.restore();
- querySelectorStub.restore();
- elStub.restore();
- frameElementStub.restore();
-
- done();
- });
- });
- });
});
diff --git a/test/spec/modules/alkimiBidAdapter_spec.js b/test/spec/modules/alkimiBidAdapter_spec.js
index 1ae9bb56df4..92e5d28f42a 100644
--- a/test/spec/modules/alkimiBidAdapter_spec.js
+++ b/test/spec/modules/alkimiBidAdapter_spec.js
@@ -108,7 +108,7 @@ describe('alkimiBidAdapter', function () {
describe('buildRequests', function () {
let bidRequests = [REQUEST]
- const bidderRequest = spec.buildRequests(bidRequests, {
+ let requestData = {
auctionId: '123',
refererInfo: {
page: 'http://test.com/path.html'
@@ -119,7 +119,8 @@ describe('alkimiBidAdapter', function () {
gdprApplies: true
},
uspConsent: 'uspConsent'
- })
+ }
+ const bidderRequest = spec.buildRequests(bidRequests, requestData)
it('should return a properly formatted request with eids defined', function () {
expect(bidderRequest.data.eids).to.deep.equal(REQUEST.userIdAsEids)
@@ -138,7 +139,7 @@ describe('alkimiBidAdapter', function () {
expect(bidderRequest.method).to.equal('POST')
expect(bidderRequest.data.requestId).to.equal('123')
expect(bidderRequest.data.referer).to.equal('http://test.com/path.html')
- expect(bidderRequest.data.schain).to.deep.contains({ver: '1.0', complete: 1, nodes: [{asi: 'alkimi-onboarding.com', sid: '00001', hp: 1}]})
+ expect(bidderRequest.data.schain).to.deep.contains({ ver: '1.0', complete: 1, nodes: [{ asi: 'alkimi-onboarding.com', sid: '00001', hp: 1 }] })
expect(bidderRequest.data.signRequest.bids).to.deep.contains({ token: 'e64782a4-8e68-4c38-965b-80ccf115d46f', pos: 7, bidFloor: 0.1, width: 300, height: 250, impMediaType: 'Banner', adUnitCode: 'bannerAdUnitCode' })
expect(bidderRequest.data.signRequest.randomUUID).to.equal(undefined)
expect(bidderRequest.data.bidIds).to.deep.contains('456')
@@ -147,6 +148,17 @@ describe('alkimiBidAdapter', function () {
expect(bidderRequest.options.contentType).to.equal('application/json')
expect(bidderRequest.url).to.equal(ENDPOINT)
})
+
+ it('sends bidFloor when configured', () => {
+ const requestWithFloor = Object.assign({}, REQUEST);
+ requestWithFloor.getFloor = function (arg) {
+ if (arg.currency === 'USD' && arg.mediaType === 'banner' && JSON.stringify(arg.size) === JSON.stringify([300, 250])) {
+ return { currency: 'USD', floor: 0.3 }
+ }
+ }
+ const bidderRequestFloor = spec.buildRequests([requestWithFloor], requestData);
+ expect(bidderRequestFloor.data.signRequest.bids[0].bidFloor).to.be.equal(0.3);
+ });
})
describe('interpretResponse', function () {
diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js
index 57ce37145f4..471c76f55cf 100644
--- a/test/spec/modules/aolBidAdapter_spec.js
+++ b/test/spec/modules/aolBidAdapter_spec.js
@@ -488,6 +488,20 @@ describe('AolAdapter', function () {
expect(request.url).to.contain(NEXAGE_URL + 'dcn=2c9d2b50015c5ce9db6aeeed8b9500d6&pos=header');
});
+ it('should return One Mobile url with configured GPP data', function () {
+ let bidRequest = createCustomBidRequest({
+ params: getNexageGetBidParams()
+ });
+ bidRequest.ortb2 = {
+ regs: {
+ gpp: 'testgpp',
+ gpp_sid: [8]
+ }
+ }
+ let [request] = spec.buildRequests(bidRequest.bids, bidRequest);
+ expect(request.url).to.contain('gpp=testgpp&gpp_sid=8');
+ });
+
it('should return One Mobile url with cmd=bid option', function () {
let bidRequest = createCustomBidRequest({
params: getNexageGetBidParams()
@@ -794,6 +808,14 @@ describe('AolAdapter', function () {
'euconsent=test-consent;gdpr=1;us_privacy=test-usp-consent;');
});
+ it('should return formatted gpp privacy params when formatConsentData returns GPP data', function () {
+ formatConsentDataStub.returns({
+ gpp: 'gppstring',
+ gpp_sid: [6, 7]
+ });
+ expect(spec.formatMarketplaceDynamicParams()).to.be.equal('gpp=gppstring;gpp_sid=6%2C7;');
+ });
+
it('should return formatted params when formatKeyValues returns data', function () {
formatKeyValuesStub.returns({
param1: 'val1',
diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js
index 1ab8feceaeb..a5bd9a3592e 100644
--- a/test/spec/modules/appnexusBidAdapter_spec.js
+++ b/test/spec/modules/appnexusBidAdapter_spec.js
@@ -1630,7 +1630,10 @@ describe('AppNexusAdapter', function () {
'phone': '1234567890',
'address': '28 W 23rd St, New York, NY 10010',
'privacy_link': 'https://appnexus.com/?url=privacy_url',
- 'javascriptTrackers': ''
+ 'javascriptTrackers': '',
+ 'video': {
+ 'content': ''
+ }
};
let bidderRequest = {
bids: [{
@@ -1644,6 +1647,7 @@ describe('AppNexusAdapter', function () {
expect(result[0].native.body).to.equal('Cool description great stuff');
expect(result[0].native.cta).to.equal('Do it');
expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png');
+ expect(result[0].native.video.content).to.equal('');
});
}
@@ -1731,7 +1735,7 @@ describe('AppNexusAdapter', function () {
it('should add advertiserDomains', function () {
let responseAdvertiserId = deepClone(response);
- responseAdvertiserId.tags[0].ads[0].adomain = ['123'];
+ responseAdvertiserId.tags[0].ads[0].adomain = '123';
let bidderRequest = {
bids: [{
@@ -1741,7 +1745,7 @@ describe('AppNexusAdapter', function () {
}
let result = spec.interpretResponse({ body: responseAdvertiserId }, { bidderRequest });
expect(Object.keys(result[0].meta)).to.include.members(['advertiserDomains']);
- expect(Object.keys(result[0].meta.advertiserDomains)).to.deep.equal([]);
+ expect(result[0].meta.advertiserDomains).to.deep.equal(['123']);
});
});
diff --git a/test/spec/modules/appushBidAdapter_spec.js b/test/spec/modules/appushBidAdapter_spec.js
new file mode 100644
index 00000000000..91c50cc3dd0
--- /dev/null
+++ b/test/spec/modules/appushBidAdapter_spec.js
@@ -0,0 +1,372 @@
+import { expect } from 'chai';
+import { spec } from '../../../modules/appushBidAdapter.js';
+import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js';
+import { getUniqueIdentifierStr } from '../../../src/utils.js';
+
+const bidder = 'appush'
+
+describe('AppushBidAdapter', function () {
+ const bids = [
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[300, 250]]
+ }
+ },
+ params: {
+ placementId: 'testBanner',
+ }
+ },
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [VIDEO]: {
+ playerSize: [[300, 300]],
+ minduration: 5,
+ maxduration: 60
+ }
+ },
+ params: {
+ placementId: 'testVideo',
+ }
+ },
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [NATIVE]: {
+ native: {
+ title: {
+ required: true
+ },
+ body: {
+ required: true
+ },
+ icon: {
+ required: true,
+ size: [64, 64]
+ }
+ }
+ }
+ },
+ params: {
+ placementId: 'testNative',
+ }
+ }
+ ];
+
+ const invalidBid = {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[300, 250]]
+ }
+ },
+ params: {
+
+ }
+ }
+
+ const bidderRequest = {
+ uspConsent: '1---',
+ gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ refererInfo: {
+ referer: 'https://test.com'
+ }
+ };
+
+ describe('isBidRequestValid', function () {
+ it('Should return true if there are bidId, params and key parameters present', function () {
+ expect(spec.isBidRequestValid(bids[0])).to.be.true;
+ });
+ it('Should return false if at least one of parameters is not present', function () {
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let serverRequest = spec.buildRequests(bids, bidderRequest);
+
+ it('Creates a ServerRequest object with method, URL and data', function () {
+ expect(serverRequest).to.exist;
+ expect(serverRequest.method).to.exist;
+ expect(serverRequest.url).to.exist;
+ expect(serverRequest.data).to.exist;
+ });
+
+ it('Returns POST method', function () {
+ expect(serverRequest.method).to.equal('POST');
+ });
+
+ it('Returns valid URL', function () {
+ expect(serverRequest.url).to.equal('https://hb.appush.com/pbjs');
+ });
+
+ it('Returns general data 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',
+ 'ccpa',
+ 'gdpr',
+ 'tmax'
+ );
+ expect(data.deviceWidth).to.be.a('number');
+ expect(data.deviceHeight).to.be.a('number');
+ expect(data.language).to.be.a('string');
+ expect(data.secure).to.be.within(0, 1);
+ expect(data.host).to.be.a('string');
+ expect(data.page).to.be.a('string');
+ expect(data.coppa).to.be.a('number');
+ expect(data.gdpr).to.be.a('string');
+ expect(data.ccpa).to.be.a('string');
+ expect(data.tmax).to.be.a('number');
+ expect(data.placements).to.have.lengthOf(3);
+ });
+
+ it('Returns valid placements', function () {
+ const { placements } = serverRequest.data;
+ for (let i = 0, len = placements.length; i < len; i++) {
+ const placement = placements[i];
+ expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']);
+ expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]);
+ expect(placement.bidId).to.be.a('string');
+ expect(placement.schain).to.be.an('object');
+ expect(placement.bidfloor).to.exist.and.to.equal(0);
+ expect(placement.type).to.exist.and.to.equal('publisher');
+
+ if (placement.adFormat === BANNER) {
+ expect(placement.sizes).to.be.an('array');
+ }
+ switch (placement.adFormat) {
+ case BANNER:
+ expect(placement.sizes).to.be.an('array');
+ break;
+ case VIDEO:
+ expect(placement.playerSize).to.be.an('array');
+ expect(placement.minduration).to.be.an('number');
+ expect(placement.maxduration).to.be.an('number');
+ break;
+ case NATIVE:
+ expect(placement.native).to.be.an('object');
+ break;
+ }
+ }
+ });
+
+ it('Returns data with gdprConsent and without uspConsent', function () {
+ delete bidderRequest.uspConsent;
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ let data = serverRequest.data;
+ expect(data.gdpr).to.exist;
+ expect(data.gdpr).to.be.a('string');
+ expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
+ expect(data.ccpa).to.not.exist;
+ delete bidderRequest.gdprConsent;
+ });
+
+ it('Returns data with uspConsent and without gdprConsent', function () {
+ bidderRequest.uspConsent = '1---';
+ delete bidderRequest.gdprConsent;
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ let data = serverRequest.data;
+ expect(data.ccpa).to.exist;
+ expect(data.ccpa).to.be.a('string');
+ expect(data.ccpa).to.equal(bidderRequest.uspConsent);
+ expect(data.gdpr).to.not.exist;
+ });
+
+ it('Returns empty data if no valid requests are passed', function () {
+ serverRequest = spec.buildRequests([], bidderRequest);
+ let data = serverRequest.data;
+ expect(data.placements).to.be.an('array').that.is.empty;
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('Should interpret banner response', function () {
+ const banner = {
+ body: [{
+ mediaType: 'banner',
+ width: 300,
+ height: 250,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let bannerResponses = spec.interpretResponse(banner);
+ expect(bannerResponses).to.be.an('array').that.is.not.empty;
+ let dataItem = bannerResponses[0];
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
+ expect(dataItem.requestId).to.equal(banner.body[0].requestId);
+ expect(dataItem.cpm).to.equal(banner.body[0].cpm);
+ expect(dataItem.width).to.equal(banner.body[0].width);
+ expect(dataItem.height).to.equal(banner.body[0].height);
+ expect(dataItem.ad).to.equal(banner.body[0].ad);
+ expect(dataItem.ttl).to.equal(banner.body[0].ttl);
+ expect(dataItem.creativeId).to.equal(banner.body[0].creativeId);
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal(banner.body[0].currency);
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should interpret video response', function () {
+ const video = {
+ body: [{
+ vastUrl: 'test.com',
+ mediaType: 'video',
+ cpm: 0.5,
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let videoResponses = spec.interpretResponse(video);
+ expect(videoResponses).to.be.an('array').that.is.not.empty;
+
+ let dataItem = videoResponses[0];
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId',
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
+ expect(dataItem.cpm).to.equal(0.5);
+ expect(dataItem.vastUrl).to.equal('test.com');
+ expect(dataItem.ttl).to.equal(120);
+ expect(dataItem.creativeId).to.equal('2');
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should interpret native response', function () {
+ const native = {
+ body: [{
+ mediaType: 'native',
+ native: {
+ clickUrl: 'test.com',
+ title: 'Test',
+ image: 'test.com',
+ impressionTrackers: ['test.com'],
+ },
+ ttl: 120,
+ cpm: 0.4,
+ requestId: '23fhj33i987f',
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let nativeResponses = spec.interpretResponse(native);
+ expect(nativeResponses).to.be.an('array').that.is.not.empty;
+
+ let dataItem = nativeResponses[0];
+ expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta');
+ expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image')
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
+ expect(dataItem.cpm).to.equal(0.4);
+ expect(dataItem.native.clickUrl).to.equal('test.com');
+ expect(dataItem.native.title).to.equal('Test');
+ expect(dataItem.native.image).to.equal('test.com');
+ expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty;
+ expect(dataItem.native.impressionTrackers[0]).to.equal('test.com');
+ expect(dataItem.ttl).to.equal(120);
+ expect(dataItem.creativeId).to.equal('2');
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should return an empty array if invalid banner response is passed', function () {
+ const invBanner = {
+ body: [{
+ width: 300,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+
+ let serverResponses = spec.interpretResponse(invBanner);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid video response is passed', function () {
+ const invVideo = {
+ body: [{
+ mediaType: 'video',
+ cpm: 0.5,
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invVideo);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid native response is passed', function () {
+ const invNative = {
+ body: [{
+ mediaType: 'native',
+ clickUrl: 'test.com',
+ title: 'Test',
+ impressionTrackers: ['test.com'],
+ ttl: 120,
+ requestId: '23fhj33i987f',
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invNative);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid response is passed', function () {
+ const invalid = {
+ body: [{
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invalid);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ });
+});
diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js
index b2193f350ce..52639c39baf 100644
--- a/test/spec/modules/connectIdSystem_spec.js
+++ b/test/spec/modules/connectIdSystem_spec.js
@@ -31,7 +31,11 @@ describe('Yahoo ConnectID Submodule', () => {
gdprApplies: 1,
consentString: 'GDPR_CONSENT_STRING'
},
- uspConsent: 'USP_CONSENT_STRING'
+ uspConsent: 'USP_CONSENT_STRING',
+ gppConsent: {
+ gppString: 'header~section6~section7',
+ applicableSections: [6, 7]
+ }
};
});
@@ -157,7 +161,9 @@ describe('Yahoo ConnectID Submodule', () => {
'1p': '0',
gdpr: '1',
gdpr_consent: consentData.gdpr.consentString,
- us_privacy: consentData.uspConsent
+ us_privacy: consentData.uspConsent,
+ gpp: consentData.gppConsent.gppString,
+ gpp_sid: '6%2C7'
};
const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
@@ -178,7 +184,9 @@ describe('Yahoo ConnectID Submodule', () => {
'1p': '0',
gdpr: '1',
gdpr_consent: consentData.gdpr.consentString,
- us_privacy: consentData.uspConsent
+ us_privacy: consentData.uspConsent,
+ gpp: consentData.gppConsent.gppString,
+ gpp_sid: '6%2C7'
};
const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
@@ -201,7 +209,9 @@ describe('Yahoo ConnectID Submodule', () => {
'1p': '0',
gdpr: '1',
gdpr_consent: consentData.gdpr.consentString,
- us_privacy: consentData.uspConsent
+ us_privacy: consentData.uspConsent,
+ gpp: consentData.gppConsent.gppString,
+ gpp_sid: '6%2C7'
};
const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
@@ -221,7 +231,9 @@ describe('Yahoo ConnectID Submodule', () => {
'1p': '0',
gdpr: '1',
gdpr_consent: consentData.gdpr.consentString,
- us_privacy: consentData.uspConsent
+ us_privacy: consentData.uspConsent,
+ gpp: consentData.gppConsent.gppString,
+ gpp_sid: '6%2C7'
};
const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]);
diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js
index 6aed670a563..8cbd6907890 100644
--- a/test/spec/modules/feedadBidAdapter_spec.js
+++ b/test/spec/modules/feedadBidAdapter_spec.js
@@ -4,6 +4,7 @@ import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js';
import {server} from 'test/mocks/xhr.js';
const CODE = 'feedad';
+const EXPECTED_ADAPTER_VERSION = '1.0.5';
describe('FeedAdAdapter', function () {
describe('Public API', function () {
@@ -300,6 +301,20 @@ describe('FeedAdAdapter', function () {
expect(result.data.gdprApplies).to.equal(request.gdprConsent.gdprApplies);
expect(result.data.consentIabTcf).to.equal(request.gdprConsent.consentString);
});
+ it('should include adapter and prebid version', function () {
+ let bid = {
+ code: 'feedad',
+ mediaTypes: {
+ banner: {
+ sizes: [[320, 250]]
+ }
+ },
+ params: {clientToken: 'clientToken', placementId: 'placement-id'}
+ };
+ let result = spec.buildRequests([bid], bidderRequest);
+ expect(result.data.bids[0].params.prebid_adapter_version).to.equal(EXPECTED_ADAPTER_VERSION);
+ expect(result.data.bids[0].params.prebid_sdk_version).to.equal('$prebid.version$');
+ });
});
describe('interpretResponse', function () {
@@ -482,6 +497,12 @@ describe('FeedAdAdapter', function () {
expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, it)).not.to.throw;
});
});
+
+ it('should return empty array if the body extension is null', function () {
+ const response = mockServerResponse({ext: null});
+ const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, response);
+ expect(result).to.deep.equal([]);
+ });
});
describe('event tracking calls', function () {
@@ -617,7 +638,8 @@ describe('FeedAdAdapter', function () {
prebid_bid_id: bidId,
prebid_transaction_id: transactionId,
referer,
- sdk_version: '1.0.4'
+ prebid_adapter_version: EXPECTED_ADAPTER_VERSION,
+ prebid_sdk_version: '$prebid.version$',
};
subject(data);
expect(server.requests.length).to.equal(1);
diff --git a/test/spec/modules/lotamePanoramaIdSystem_spec.js b/test/spec/modules/lotamePanoramaIdSystem_spec.js
index 5dc055ac080..ea538db08e1 100644
--- a/test/spec/modules/lotamePanoramaIdSystem_spec.js
+++ b/test/spec/modules/lotamePanoramaIdSystem_spec.js
@@ -18,6 +18,7 @@ describe('LotameId', function() {
let removeFromLocalStorageStub;
let timeStampStub;
let uspConsentDataStub;
+ let requestHost;
const nowTimestamp = new Date().getTime();
@@ -33,6 +34,11 @@ describe('LotameId', function() {
);
timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp);
uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData');
+ if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
+ requestHost = 'https://c.ltmsphrcl.net/id';
+ } else {
+ requestHost = 'https://id.crwdcntrl.net/id';
+ }
});
afterEach(function () {
@@ -69,7 +75,7 @@ describe('LotameId', function() {
});
it('should call the remote server when getId is called', function () {
- expect(request.url).to.be.eq('https://id.crwdcntrl.net/id');
+ expect(request.url).to.be.eq(`${requestHost}`);
expect(callBackSpy.calledOnce).to.be.true;
});
@@ -439,7 +445,7 @@ describe('LotameId', function() {
it('should pass the gdpr consent string back', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven'
+ `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven`
);
});
});
@@ -471,7 +477,7 @@ describe('LotameId', function() {
it('should pass the gdpr consent string back', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven'
+ `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven`
);
});
});
@@ -503,7 +509,7 @@ describe('LotameId', function() {
it('should pass the gdpr consent string back', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven'
+ `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven`
);
});
});
@@ -531,7 +537,7 @@ describe('LotameId', function() {
it('should not include the gdpr consent string on the url', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=true'
+ `${requestHost}?gdpr_applies=true`
);
});
});
@@ -560,7 +566,7 @@ describe('LotameId', function() {
it('should pass the gdpr consent string back', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven'
+ `${requestHost}?gdpr_consent=consentGiven`
);
});
});
@@ -589,7 +595,7 @@ describe('LotameId', function() {
it('should pass the gdpr consent string back', function() {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven'
+ `${requestHost}?gdpr_consent=consentGiven`
);
});
});
@@ -613,7 +619,7 @@ describe('LotameId', function() {
});
it('should pass the gdpr consent string back', function() {
- expect(request.url).to.be.eq('https://id.crwdcntrl.net/id');
+ expect(request.url).to.be.eq(`${requestHost}`);
});
});
@@ -835,7 +841,7 @@ describe('LotameId', function() {
it('should pass the usp consent string and client id back', function () {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=false&us_privacy=1NNN&c=1234'
+ `${requestHost}?gdpr_applies=false&us_privacy=1NNN&c=1234`
);
});
@@ -923,7 +929,7 @@ describe('LotameId', function() {
it('should pass client id back', function () {
expect(request.url).to.be.eq(
- 'https://id.crwdcntrl.net/id?gdpr_applies=false&c=1234'
+ `${requestHost}?gdpr_applies=false&c=1234`
);
});
diff --git a/test/spec/modules/orbitsoftBidAdapter_spec.js b/test/spec/modules/orbitsoftBidAdapter_spec.js
new file mode 100644
index 00000000000..8c3187e9324
--- /dev/null
+++ b/test/spec/modules/orbitsoftBidAdapter_spec.js
@@ -0,0 +1,255 @@
+import {expect} from 'chai';
+import {spec} from 'modules/orbitsoftBidAdapter.js';
+
+const ENDPOINT_URL = 'https://orbitsoft.com/php/ads/hb.phps';
+const REFERRER_URL = 'http://referrer.url/?_=';
+
+describe('Orbitsoft adapter', function () {
+ describe('implementation', function () {
+ describe('for requests', function () {
+ it('should accept valid bid', function () {
+ let validBid = {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ },
+ isValid = spec.isBidRequestValid(validBid);
+
+ expect(isValid).to.equal(true);
+ });
+
+ it('should reject invalid bid', function () {
+ let invalidBid = {
+ bidder: 'orbitsoft'
+ },
+ isValid = spec.isBidRequestValid(invalidBid);
+
+ expect(isValid).to.equal(false);
+ });
+ });
+ describe('for requests', function () {
+ it('should accept valid bid with styles', function () {
+ let validBid = {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL,
+ style: {
+ title: {
+ family: 'Tahoma',
+ size: 'medium',
+ weight: 'normal',
+ style: 'normal',
+ color: '0053F9'
+ },
+ description: {
+ family: 'Tahoma',
+ size: 'medium',
+ weight: 'normal',
+ style: 'normal',
+ color: '0053F9'
+ },
+ url: {
+ family: 'Tahoma',
+ size: 'medium',
+ weight: 'normal',
+ style: 'normal',
+ color: '0053F9'
+ },
+ colors: {
+ background: 'ffffff',
+ border: 'E0E0E0',
+ link: '5B99FE'
+ }
+ }
+ },
+ refererInfo: {referer: REFERRER_URL},
+ },
+ isValid = spec.isBidRequestValid(validBid);
+ expect(isValid).to.equal(true);
+
+ let buildRequest = spec.buildRequests([validBid])[0];
+ let requestUrl = buildRequest.url;
+ let requestUrlParams = buildRequest.data;
+ expect(requestUrl).to.equal(ENDPOINT_URL);
+ expect(requestUrlParams).have.property('f1', 'Tahoma');
+ expect(requestUrlParams).have.property('fs1', 'medium');
+ expect(requestUrlParams).have.property('w1', 'normal');
+ expect(requestUrlParams).have.property('s1', 'normal');
+ expect(requestUrlParams).have.property('c3', '0053F9');
+ expect(requestUrlParams).have.property('f2', 'Tahoma');
+ expect(requestUrlParams).have.property('fs2', 'medium');
+ expect(requestUrlParams).have.property('w2', 'normal');
+ expect(requestUrlParams).have.property('s2', 'normal');
+ expect(requestUrlParams).have.property('c4', '0053F9');
+ expect(requestUrlParams).have.property('f3', 'Tahoma');
+ expect(requestUrlParams).have.property('fs3', 'medium');
+ expect(requestUrlParams).have.property('w3', 'normal');
+ expect(requestUrlParams).have.property('s3', 'normal');
+ expect(requestUrlParams).have.property('c5', '0053F9');
+ expect(requestUrlParams).have.property('c2', 'ffffff');
+ expect(requestUrlParams).have.property('c1', 'E0E0E0');
+ expect(requestUrlParams).have.property('c6', '5B99FE');
+ });
+
+ it('should accept valid bid with custom params', function () {
+ let validBid = {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL,
+ customParams: {
+ cacheBuster: 'bf4d7c1',
+ clickUrl: 'http://testclickurl.com'
+ }
+ },
+ refererInfo: {referer: REFERRER_URL},
+ },
+ isValid = spec.isBidRequestValid(validBid);
+ expect(isValid).to.equal(true);
+
+ let buildRequest = spec.buildRequests([validBid])[0];
+ let requestUrlCustomParams = buildRequest.data;
+ expect(requestUrlCustomParams).have.property('c.cacheBuster', 'bf4d7c1');
+ expect(requestUrlCustomParams).have.property('c.clickUrl', 'http://testclickurl.com');
+ });
+
+ it('should reject invalid bid without requestUrl', function () {
+ let invalidBid = {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123'
+ }
+ },
+ isValid = spec.isBidRequestValid(invalidBid);
+
+ expect(isValid).to.equal(false);
+ });
+
+ it('should reject invalid bid without placementId', function () {
+ let invalidBid = {
+ bidder: 'orbitsoft',
+ params: {
+ requestUrl: ENDPOINT_URL
+ }
+ },
+ isValid = spec.isBidRequestValid(invalidBid);
+
+ expect(isValid).to.equal(false);
+ });
+ });
+ describe('bid responses', function () {
+ it('should return complete bid response', function () {
+ let serverResponse = {
+ body: {
+ callback_uid: '265b29b70cc106',
+ cpm: 0.5,
+ width: 240,
+ height: 240,
+ content_url: 'https://orbitsoft.com/php/ads/hb.html',
+ adomain: ['test.adomain.tld']
+ }
+ };
+
+ let bidRequests = [
+ {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ }
+ ];
+ let bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});
+ expect(bids).to.be.lengthOf(1);
+ expect(bids[0].cpm).to.equal(serverResponse.body.cpm);
+ expect(bids[0].width).to.equal(serverResponse.body.width);
+ expect(bids[0].height).to.equal(serverResponse.body.height);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].adUrl).to.have.length.above(1);
+ expect(bids[0].adUrl).to.have.string('https://orbitsoft.com/php/ads/hb.html');
+ expect(Object.keys(bids[0].meta)).to.include.members(['advertiserDomains']);
+ expect(bids[0].meta.advertiserDomains).to.deep.equal(serverResponse.body.adomain);
+ });
+
+ it('should return empty bid response', function () {
+ let bidRequests = [
+ {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ }
+ ];
+ let serverResponse = {
+ body: {
+ callback_uid: '265b29b70cc106',
+ cpm: 0
+ }
+ },
+ bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});
+
+ expect(bids).to.be.lengthOf(0);
+ });
+
+ it('should return empty bid response on incorrect size', function () {
+ let bidRequests = [
+ {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ }
+ ];
+ let serverResponse = {
+ body: {
+ callback_uid: '265b29b70cc106',
+ cpm: 1.5,
+ width: 0,
+ height: 0
+ }
+ },
+ bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});
+
+ expect(bids).to.be.lengthOf(0);
+ });
+
+ it('should return empty bid response with error', function () {
+ let bidRequests = [
+ {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ }
+ ];
+ let serverResponse = {error: 'error'},
+ bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});
+
+ expect(bids).to.be.lengthOf(0);
+ });
+
+ it('should return empty bid response on empty body', function () {
+ let bidRequests = [
+ {
+ bidder: 'orbitsoft',
+ params: {
+ placementId: '123',
+ requestUrl: ENDPOINT_URL
+ }
+ }
+ ];
+ let serverResponse = {},
+ bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});
+
+ expect(bids).to.be.lengthOf(0);
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js
index d0efd5f1f75..cfdd3365269 100644
--- a/test/spec/modules/seedtagBidAdapter_spec.js
+++ b/test/spec/modules/seedtagBidAdapter_spec.js
@@ -395,6 +395,52 @@ describe('Seedtag Adapter', function () {
expect(payload.schain).to.not.exist;
});
});
+
+ describe('GPP param', function () {
+ it('should be added to payload when bidderRequest has gppConsent param', function () {
+ const gppConsent = {
+ gppString: 'someGppString',
+ applicableSections: [7]
+ }
+ bidderRequest['gppConsent'] = gppConsent
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.gppConsent).to.exist;
+ expect(data.gppConsent.gppString).to.equal(gppConsent.gppString);
+ expect(data.gppConsent.applicableSections[0]).to.equal(gppConsent.applicableSections[0]);
+ });
+
+ it('should be undefined on payload when bidderRequest has not gppConsent param', function () {
+ bidderRequest.gppConsent = undefined
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.gppConsent).to.be.undefined;
+ });
+
+ it('should be added to payload when bidderRequest has ortb2 param', function () {
+ const ortb2 = {
+ regs: {
+ gpp: 'someGppString',
+ gpp_sid: [7]
+ }
+ }
+ bidderRequest['gppConsent'] = undefined
+ bidderRequest['ortb2'] = ortb2;
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.gppConsent).to.exist;
+ expect(data.gppConsent.gppString).to.equal(ortb2.regs.gpp);
+ expect(data.gppConsent.applicableSections[0]).to.equal(ortb2.regs.gpp_sid[0]);
+ });
+
+ it('should be added to payload when bidderRequest has neither gppConsent nor ortb2', function () {
+ bidderRequest['ortb2'] = undefined;
+ bidderRequest['gppConsent'] = undefined;
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ const data = JSON.parse(request.data);
+ expect(data.gppConsent).to.be.undefined;
+ });
+ });
});
describe('interpret response method', function () {
@@ -533,11 +579,11 @@ describe('Seedtag Adapter', function () {
const timeoutUrl = getTimeoutUrl(timeoutData);
expect(timeoutUrl).to.equal(
'https://s.seedtag.com/se/hb/timeout?publisherToken=' +
- params.publisherId +
- '&adUnitId=' +
- params.adUnitId +
- '&timeout=' +
- timeout
+ params.publisherId +
+ '&adUnitId=' +
+ params.adUnitId +
+ '&timeout=' +
+ timeout
);
});
@@ -549,11 +595,11 @@ describe('Seedtag Adapter', function () {
expect(
utils.triggerPixel.calledWith(
'https://s.seedtag.com/se/hb/timeout?publisherToken=' +
- params.publisherId +
- '&adUnitId=' +
- params.adUnitId +
- '&timeout=' +
- timeout
+ params.publisherId +
+ '&adUnitId=' +
+ params.adUnitId +
+ '&timeout=' +
+ timeout
)
).to.equal(true);
});
diff --git a/test/spec/modules/smartxBidAdapter_spec.js b/test/spec/modules/smartxBidAdapter_spec.js
index 5bd08064c79..c3d0711632e 100644
--- a/test/spec/modules/smartxBidAdapter_spec.js
+++ b/test/spec/modules/smartxBidAdapter_spec.js
@@ -374,6 +374,16 @@ describe('The smartx adapter', function () {
}
})
});
+
+ it('should pass sitekey param', function () {
+ var request;
+
+ bid.params.sitekey = 'foo'
+
+ request = spec.buildRequests([bid], bidRequestObj)[0];
+
+ expect(request.data.site.content.ext.sitekey).to.equal('foo');
+ });
});
describe('interpretResponse', function () {
diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js
index a3a765d28cf..17cc5fc0213 100644
--- a/test/spec/modules/taboolaBidAdapter_spec.js
+++ b/test/spec/modules/taboolaBidAdapter_spec.js
@@ -148,7 +148,8 @@ describe('Taboola Adapter', function () {
},
'tagid': commonBidRequest.params.tagId,
'bidfloor': null,
- 'bidfloorcur': 'USD'
+ 'bidfloorcur': 'USD',
+ 'ext': {}
}],
'site': {
'id': commonBidRequest.params.publisherId,
@@ -168,7 +169,8 @@ describe('Taboola Adapter', function () {
'buyeruid': 0,
'ext': {},
},
- 'regs': {'coppa': 0, 'ext': {}}
+ 'regs': {'coppa': 0, 'ext': {}},
+ 'ext': {}
};
const res = spec.buildRequests([defaultBidRequest], commonBidderRequest);
@@ -245,7 +247,24 @@ describe('Taboola Adapter', function () {
const res = spec.buildRequests([bidRequest], commonBidderRequest);
const resData = JSON.parse(res.data);
- expect(resData.imp[0].position).to.deep.equal(2);
+ expect(resData.imp[0].banner.pos).to.deep.equal(2);
+ });
+
+ it('should pass gpid if configured', function () {
+ const ortb2Imp = {
+ ext: {
+ gpid: '/homepage/#1'
+ }
+ }
+ const bidRequest = {
+ ...defaultBidRequest,
+ ortb2Imp: ortb2Imp,
+ params: {...commonBidRequest.params}
+ };
+
+ const res = spec.buildRequests([bidRequest], commonBidderRequest);
+ const resData = JSON.parse(res.data);
+ expect(resData.imp[0].ext.gpid).to.deep.equal('/homepage/#1');
});
it('should pass bidder timeout', function () {
@@ -288,7 +307,7 @@ describe('Taboola Adapter', function () {
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
const resData = JSON.parse(res.data);
- expect(resData.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType);
+ expect(resData.ext.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType);
});
});
diff --git a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js
index 4377e989851..e08353f5b8d 100644
--- a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js
+++ b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js
@@ -66,7 +66,28 @@ function getUtilsMock() {
const sharedUtils = { videoEvents };
+function addDiv() {
+ const div = document.createElement('div');
+ div.setAttribute('id', 'test');
+ document.body.appendChild(div);
+}
+
+function removeDiv() {
+ const div = document.getElementById('test');
+ if (div) {
+ div.remove();
+ }
+}
+
describe('JWPlayerProvider', function () {
+ beforeEach(() => {
+ addDiv();
+ });
+
+ afterEach(() => {
+ removeDiv();
+ });
+
describe('init', function () {
let config;
let adState;
@@ -75,7 +96,7 @@ describe('JWPlayerProvider', function () {
let utilsMock;
beforeEach(() => {
- config = {};
+ config = { divId: 'test' };
adState = adStateFactory();
timeState = timeStateFactory();
callbackStorage = callbackStorageFactory();
@@ -104,7 +125,21 @@ describe('JWPlayerProvider', function () {
expect(payload.errorCode).to.be.equal(-2);
});
- it('should instantiate the player when uninstantied', function () {
+ it('should trigger failure when div is missing', function () {
+ removeDiv();
+ let jwplayerMock = () => {};
+ const provider = JWPlayerProvider(config, jwplayerMock, adState, timeState, callbackStorage, utilsMock, sharedUtils);
+ const setupFailed = sinon.spy();
+ provider.onEvent(SETUP_FAILED, setupFailed, {});
+ provider.init();
+ expect(setupFailed.calledOnce).to.be.true;
+ const payload = setupFailed.args[0][1];
+ expect(payload.errorCode).to.be.equal(-3);
+ addDiv();
+ addDiv();
+ });
+
+ it('should instantiate the player when uninstantiated', function () {
const player = getPlayerMock();
config.playerConfig = {};
const setupSpy = player.setup = sinon.spy();
@@ -113,7 +148,7 @@ describe('JWPlayerProvider', function () {
expect(setupSpy.calledOnce).to.be.true;
});
- it('should trigger setup complete when player is already instantied', function () {
+ it('should trigger setup complete when player is already instantiated', function () {
const player = getPlayerMock();
player.getState = () => 'idle';
const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adState, timeState, callbackStorage, utilsMock, sharedUtils);
@@ -151,7 +186,7 @@ describe('JWPlayerProvider', function () {
const test_playback_method = PLAYBACK_METHODS.CLICK_TO_PLAY;
const test_skip = 0;
- const config = {};
+ const config = { divId: 'test' };
const player = getPlayerMock();
const utils = getUtilsMock();
@@ -230,9 +265,9 @@ describe('JWPlayerProvider', function () {
duration: test_duration,
playbackMode: test_playback_mode
})
- }
+ };
- const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeState, {}, utils, sharedUtils);
+ const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeState, {}, utils, sharedUtils);
provider.init();
let content = provider.getOrtbContent();
@@ -260,7 +295,7 @@ describe('JWPlayerProvider', function () {
it('should call playAd', function () {
const player = getPlayerMock();
const playAdSpy = player.playAd = sinon.spy();
- const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), {}, {}, {}, {}, sharedUtils);
+ const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), {}, {}, {}, {}, sharedUtils);
provider.init();
provider.setAdTagUrl('tag');
expect(playAdSpy.called).to.be.true;
@@ -273,7 +308,7 @@ describe('JWPlayerProvider', function () {
it('should register event listener on player', function () {
const player = getPlayerMock();
const onSpy = player.on = sinon.spy();
- const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils);
+ const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils);
provider.init();
const callback = () => {};
provider.onEvent(PLAY, callback, {});
@@ -285,7 +320,7 @@ describe('JWPlayerProvider', function () {
it('should remove event listener on player', function () {
const player = getPlayerMock();
const offSpy = player.off = sinon.spy();
- const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), utils, sharedUtils);
+ const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), utils, sharedUtils);
provider.init();
const callback = () => {};
provider.onEvent(AD_IMPRESSION, callback, {});
@@ -301,7 +336,7 @@ describe('JWPlayerProvider', function () {
const player = getPlayerMock();
const removeSpy = player.remove = sinon.spy();
player.remove = removeSpy;
- const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils);
+ const provider = JWPlayerProvider({ divId: 'test' }, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils);
provider.init();
provider.destroy();
provider.destroy();
diff --git a/test/spec/modules/yahoosspBidAdapter_spec.js b/test/spec/modules/yahoosspBidAdapter_spec.js
index 32bc94b73fa..01583ac30dc 100644
--- a/test/spec/modules/yahoosspBidAdapter_spec.js
+++ b/test/spec/modules/yahoosspBidAdapter_spec.js
@@ -3,6 +3,7 @@ import { config } from 'src/config.js';
import { BANNER, VIDEO } from 'src/mediaTypes.js';
import { spec } from 'modules/yahoosspBidAdapter.js';
import {createEidsArray} from '../../../modules/userId/eids';
+import {deepClone} from '../../../src/utils';
const DEFAULT_BID_ID = '84ab500420319d';
const DEFAULT_BID_DCN = '2093845709823475';
@@ -713,7 +714,7 @@ describe('YahooSSP Bid Adapter:', () => {
});
});
- describe('GDPR & Consent:', () => {
+ describe('GDPR & Consent & GPP:', () => {
it('should return request objects that do not send cookies if purpose 1 consent is not provided', () => {
const { validBidRequests, bidderRequest } = generateBuildRequestMock({});
bidderRequest.gdprConsent = {
@@ -731,6 +732,20 @@ describe('YahooSSP Bid Adapter:', () => {
const options = spec.buildRequests(validBidRequests, bidderRequest)[0].options;
expect(options.withCredentials).to.be.false;
});
+
+ it('adds the ortb2 gpp consent info to the request', function () {
+ const { validBidRequests, bidderRequest } = generateBuildRequestMock({});
+ const ortb2 = {
+ regs: {
+ gpp: 'somegppstring',
+ gpp_sid: [6, 7]
+ }
+ };
+ let clonedBidderRequest = {...bidderRequest, ortb2};
+ const data = spec.buildRequests(validBidRequests, clonedBidderRequest)[0].data;
+ expect(data.regs.ext.gpp).to.equal('somegppstring');
+ expect(data.regs.ext.gpp_sid).to.eql([6, 7]);
+ });
});
describe('Endpoint & Impression Request Mode:', () => {
diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js
index 07d42df1319..e5151cf789c 100644
--- a/test/spec/modules/yieldlabBidAdapter_spec.js
+++ b/test/spec/modules/yieldlabBidAdapter_spec.js
@@ -1,7 +1,7 @@
import { config } from 'src/config.js';
-import { expect } from 'chai'
-import { spec } from 'modules/yieldlabBidAdapter.js'
-import { newBidder } from 'src/adapters/bidderFactory.js'
+import { expect } from 'chai';
+import { spec } from 'modules/yieldlabBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
const DEFAULT_REQUEST = () => ({
bidder: 'yieldlab',
@@ -11,11 +11,11 @@ const DEFAULT_REQUEST = () => ({
targeting: {
key1: 'value1',
key2: 'value2',
- notDoubleEncoded: 'value3,value4'
+ notDoubleEncoded: 'value3,value4',
},
customParams: {
extraParam: true,
- foo: 'bar'
+ foo: 'bar',
},
extId: 'abc',
iabContent: {
@@ -31,8 +31,8 @@ const DEFAULT_REQUEST = () => ({
cat: ['cat1', 'cat2,ppp', 'cat3|||//'],
context: '7',
keywords: ['k1,', 'k2..'],
- live: '0'
- }
+ live: '0',
+ },
},
bidderRequestId: '143346cf0f1731',
auctionId: '2e41f65424c87c',
@@ -43,14 +43,14 @@ const DEFAULT_REQUEST = () => ({
source: 'netid.de',
uids: [{
id: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
- atype: 1
- }]
+ atype: 1,
+ }],
}, {
source: 'digitrust.de',
uids: [{
id: 'd8aa10fa-d86c-451d-aad8-5f16162a9e64',
- atype: 2
- }]
+ atype: 2,
+ }],
}],
schain: {
ver: '1.0',
@@ -59,32 +59,32 @@ const DEFAULT_REQUEST = () => ({
{
asi: 'indirectseller.com',
sid: '1',
- hp: 1
+ hp: 1,
},
{
asi: 'indirectseller2.com',
name: 'indirectseller2 name with comma , and bang !',
sid: '2',
- hp: 1
- }
- ]
- }
-})
+ hp: 1,
+ },
+ ],
+ },
+});
const VIDEO_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
mediaTypes: {
video: {
playerSize: [[640, 480]],
- context: 'instream'
- }
- }
-})
+ context: 'instream',
+ },
+ },
+});
const NATIVE_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
mediaTypes: {
- native: {}
- }
-})
+ native: {},
+ },
+});
const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
params: {
@@ -119,7 +119,7 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
name: 'bar',
cattax: 532,
cat: [1, 'foo', true],
- domain: 'producer.test'
+ domain: 'producer.test',
},
data: {
id: 'foo',
@@ -129,8 +129,8 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
value: 'bar',
ext: {
foo: {
- bar: 'bar'
- }
+ bar: 'bar',
+ },
},
}, {
name: 'foo2',
@@ -139,27 +139,27 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), {
test: {
nums: {
int: 123,
- float: 123.123
+ float: 123.123,
},
bool: true,
- string: 'foo2'
- }
- }
+ string: 'foo2',
+ },
+ },
}],
},
network: {
id: 'foo',
name: 'bar',
- domain: 'network.test'
+ domain: 'network.test',
},
channel: {
id: 'bar',
name: 'foo',
- domain: 'channel.test'
- }
- }
- }
-})
+ domain: 'channel.test',
+ },
+ },
+ },
+});
const RESPONSE = {
advertiser: 'yieldlab',
@@ -169,173 +169,173 @@ const RESPONSE = {
price: 1,
pid: 2222,
adsize: '728x90',
- adtype: 'BANNER'
-}
+ adtype: 'BANNER',
+};
const NATIVE_RESPONSE = Object.assign({}, RESPONSE, {
adtype: 'NATIVE',
native: {
link: {
- url: 'https://www.yieldlab.de'
+ url: 'https://www.yieldlab.de',
},
assets: [
{
id: 1,
title: {
- text: 'This is a great headline'
- }
+ text: 'This is a great headline',
+ },
},
{
id: 2,
img: {
url: 'https://localhost:8080/yl-logo100x100.jpg',
w: 100,
- h: 100
- }
+ h: 100,
+ },
},
{
id: 3,
data: {
- value: 'Native body value'
- }
- }
+ value: 'Native body value',
+ },
+ },
],
imptrackers: [
'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12',
'http://localhost:8080/md/1111/9efa4e76-2030-4f04-bb9f-322541f8d611?mdata=false&pvid=false&ids=x:1',
- 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0'
- ]
- }
-})
+ 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0',
+ ],
+ },
+});
const VIDEO_RESPONSE = Object.assign({}, RESPONSE, {
- adtype: 'VIDEO'
-})
+ adtype: 'VIDEO',
+});
const PVID_RESPONSE = Object.assign({}, VIDEO_RESPONSE, {
- pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c'
-})
+ pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c',
+});
const REQPARAMS = {
json: true,
- ts: 1234567890
-}
+ ts: 1234567890,
+};
const REQPARAMS_GDPR = Object.assign({}, REQPARAMS, {
gdpr: true,
- consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA'
-})
+ consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA',
+});
const REQPARAMS_IAB_CONTENT = Object.assign({}, REQPARAMS, {
- iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0'
-})
+ iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0',
+});
describe('yieldlabBidAdapter', () => {
describe('instantiation from spec', () => {
it('is working properly', () => {
- const yieldlabBidAdapter = newBidder(spec)
- expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function')
- })
- })
+ const yieldlabBidAdapter = newBidder(spec);
+ expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
describe('isBidRequestValid', () => {
it('should return true when all required parameters are found', () => {
const request = {
params: {
adslotId: '1111',
- supplyId: '2222'
- }
- }
- expect(spec.isBidRequestValid(request)).to.equal(true)
- })
+ supplyId: '2222',
+ },
+ };
+ expect(spec.isBidRequestValid(request)).to.equal(true);
+ });
it('should return false when required parameters are missing', () => {
- expect(spec.isBidRequestValid({})).to.equal(false)
- })
- })
+ expect(spec.isBidRequestValid({})).to.equal(false);
+ });
+ });
describe('buildRequests', () => {
- const bidRequests = [DEFAULT_REQUEST()]
+ const bidRequests = [DEFAULT_REQUEST()];
describe('default functionality', () => {
- let request
+ let request;
before(() => {
- request = spec.buildRequests(bidRequests)
- })
+ request = spec.buildRequests(bidRequests);
+ });
it('sends bid request to ENDPOINT via GET', () => {
- expect(request.method).to.equal('GET')
- })
+ expect(request.method).to.equal('GET');
+ });
it('returns a list of valid requests', () => {
- expect(request.validBidRequests).to.eql(bidRequests)
- })
+ expect(request.validBidRequests).to.eql(bidRequests);
+ });
it('passes single-encoded targeting to bid request', () => {
- expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4')
- })
+ expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4');
+ });
it('passes userids to bid request', () => {
- expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64')
- })
+ expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64');
+ });
it('passes atype to bid request', () => {
- expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2')
- })
+ expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2');
+ });
it('passes extra params to bid request', () => {
- expect(request.url).to.include('extraParam=true&foo=bar')
- })
+ expect(request.url).to.include('extraParam=true&foo=bar');
+ });
it('passes unencoded schain string to bid request', () => {
- expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,')
- })
+ expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,');
+ });
it('passes iab_content string to bid request', () => {
- expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0')
- })
+ expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0');
+ });
it('passes correct size to bid request', () => {
- expect(request.url).to.include('728x90')
- })
+ expect(request.url).to.include('728x90');
+ });
it('passes external id to bid request', () => {
- expect(request.url).to.include('id=abc')
- })
- })
+ expect(request.url).to.include('id=abc');
+ });
+ });
describe('iab_content handling', () => {
const siteConfig = {
ortb2: {
site: {
content: {
- id: 'id_from_config'
- }
- }
- }
- }
+ id: 'id_from_config',
+ },
+ },
+ },
+ };
beforeEach(() => {
- config.setConfig(siteConfig)
- })
+ config.setConfig(siteConfig);
+ });
afterEach(() => {
- config.resetConfig()
- })
+ config.resetConfig();
+ });
it('generates iab_content string from bidder params', () => {
- const request = spec.buildRequests(bidRequests)
- expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0')
- })
+ const request = spec.buildRequests(bidRequests);
+ expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0');
+ });
it('generates iab_content string from first party data if not provided in bidder params', () => {
- const requestWithoutIabContent = DEFAULT_REQUEST()
- delete requestWithoutIabContent.params.iabContent
+ const requestWithoutIabContent = DEFAULT_REQUEST();
+ delete requestWithoutIabContent.params.iabContent;
- const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}])
- expect(request.url).to.include('iab_content=id%3Aid_from_config')
- })
+ const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]);
+ expect(request.url).to.include('iab_content=id%3Aid_from_config');
+ });
it('flattens the iabContent, encodes the values, joins the keywords into one value, and than encodes the iab_content request param ', () => {
const expectedIabContentValue = encodeURIComponent(
@@ -382,18 +382,18 @@ describe('yieldlabBidAdapter', () => {
'channel.id:bar,' +
'channel.name:foo,' +
'channel.domain:channel.test'
- )
- const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS)
- expect(request.url).to.include('iab_content=' + expectedIabContentValue)
- })
- })
+ );
+ const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS);
+ expect(request.url).to.include('iab_content=' + expectedIabContentValue);
+ });
+ });
it('passes unencoded schain string to bid request when complete == 0', () => {
- const schainRequest = DEFAULT_REQUEST()
+ const schainRequest = DEFAULT_REQUEST();
schainRequest.schain.complete = 0; //
- const request = spec.buildRequests([schainRequest])
- expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,')
- })
+ const request = spec.buildRequests([schainRequest]);
+ expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,');
+ });
it('passes encoded referer to bid request', () => {
const refererRequest = spec.buildRequests(bidRequests, {
@@ -402,123 +402,123 @@ describe('yieldlabBidAdapter', () => {
numIframes: 0,
reachedTop: true,
page: 'https://www.yieldlab.de/test?with=querystring',
- stack: ['https://www.yieldlab.de/test?with=querystring']
- }
- })
+ stack: ['https://www.yieldlab.de/test?with=querystring'],
+ },
+ });
- expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring')
- })
+ expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring');
+ });
it('passes gdpr flag and consent if present', () => {
const gdprRequest = spec.buildRequests(bidRequests, {
gdprConsent: {
consentString: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA',
- gdprApplies: true
- }
- })
+ gdprApplies: true,
+ },
+ });
- expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA')
- expect(gdprRequest.url).to.include('gdpr=true')
- })
+ expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA');
+ expect(gdprRequest.url).to.include('gdpr=true');
+ });
describe('sizes handling', () => {
it('passes correct size to bid request for mediaType banner', () => {
const bannerRequest = DEFAULT_REQUEST();
bannerRequest.mediaTypes = {
banner: {
- sizes: [[123, 456]]
- }
- }
+ sizes: [[123, 456]],
+ },
+ };
// when mediaTypes is present it has precedence over the sizes field (728, 90)
- let request = spec.buildRequests([bannerRequest], REQPARAMS)
- expect(request.url).to.include('sizes')
- expect(request.url).to.include('123x456')
-
- bannerRequest.mediaTypes.banner.sizes = [123, 456]
- request = spec.buildRequests([bannerRequest], REQPARAMS)
- expect(request.url).to.include('123x456')
-
- bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]]
- request = spec.buildRequests([bannerRequest], REQPARAMS)
- expect(request.url).to.include('123x456')
- expect(request.url).to.include('320x240')
- })
+ let request = spec.buildRequests([bannerRequest], REQPARAMS);
+ expect(request.url).to.include('sizes');
+ expect(request.url).to.include('123x456');
+
+ bannerRequest.mediaTypes.banner.sizes = [123, 456];
+ request = spec.buildRequests([bannerRequest], REQPARAMS);
+ expect(request.url).to.include('123x456');
+
+ bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]];
+ request = spec.buildRequests([bannerRequest], REQPARAMS);
+ expect(request.url).to.include('123x456');
+ expect(request.url).to.include('320x240');
+ });
it('passes correct sizes to bid request when mediaType is not present', () => {
// information is taken from the top level sizes field
const sizesRequest = DEFAULT_REQUEST();
- let request = spec.buildRequests([sizesRequest], REQPARAMS)
- expect(request.url).to.include('sizes')
- expect(request.url).to.include('728x90')
+ let request = spec.buildRequests([sizesRequest], REQPARAMS);
+ expect(request.url).to.include('sizes');
+ expect(request.url).to.include('728x90');
- sizesRequest.sizes = [[728, 90]]
- request = spec.buildRequests([sizesRequest], REQPARAMS)
- expect(request.url).to.include('728x90')
+ sizesRequest.sizes = [[728, 90]];
+ request = spec.buildRequests([sizesRequest], REQPARAMS);
+ expect(request.url).to.include('728x90');
- sizesRequest.sizes = [[728, 90], [320, 240]]
- request = spec.buildRequests([sizesRequest], REQPARAMS)
- expect(request.url).to.include('728x90')
- })
+ sizesRequest.sizes = [[728, 90], [320, 240]];
+ request = spec.buildRequests([sizesRequest], REQPARAMS);
+ expect(request.url).to.include('728x90');
+ });
it('does not pass the sizes parameter for mediaType video', () => {
const videoRequest = VIDEO_REQUEST();
- let request = spec.buildRequests([videoRequest], REQPARAMS)
- expect(request.url).to.not.include('sizes')
- })
+ let request = spec.buildRequests([videoRequest], REQPARAMS);
+ expect(request.url).to.not.include('sizes');
+ });
it('does not pass the sizes parameter for mediaType native', () => {
const nativeRequest = NATIVE_REQUEST();
- let request = spec.buildRequests([nativeRequest], REQPARAMS)
- expect(request.url).to.not.include('sizes')
- })
- })
- })
+ let request = spec.buildRequests([nativeRequest], REQPARAMS);
+ expect(request.url).to.not.include('sizes');
+ });
+ });
+ });
describe('interpretResponse', () => {
- let bidRequest
+ let bidRequest;
before(() => {
- bidRequest = DEFAULT_REQUEST()
- })
+ bidRequest = DEFAULT_REQUEST();
+ });
it('handles nobid responses', () => {
- expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0)
- expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0)
- })
+ expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0);
+ expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0);
+ });
it('should get correct bid response', () => {
- const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [bidRequest], queryParams: REQPARAMS})
-
- expect(result[0].requestId).to.equal('2d925f27f5079f')
- expect(result[0].cpm).to.equal(0.01)
- expect(result[0].width).to.equal(728)
- expect(result[0].height).to.equal(90)
- expect(result[0].creativeId).to.equal('1111')
- expect(result[0].dealId).to.equal(2222)
- expect(result[0].currency).to.equal('EUR')
- expect(result[0].netRevenue).to.equal(false)
- expect(result[0].ttl).to.equal(300)
- expect(result[0].referrer).to.equal('')
- expect(result[0].meta.advertiserDomains).to.equal('yieldlab')
- expect(result[0].ad).to.include('