diff --git a/modules/.submodules.json b/modules/.submodules.json index b0c2e9b29bf..b45fb7f2303 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -45,7 +45,8 @@ "verizonMediaIdSystem", "zeotapIdPlusIdSystem", "adqueryIdSystem", - "gravitoIdSystem" + "gravitoIdSystem", + "freepassIdSystem" ], "adpod": [ "freeWheelAdserverVideo", diff --git a/modules/1plusXRtdProvider.js b/modules/1plusXRtdProvider.js index 390f4f4cd81..665a0f2b35e 100644 --- a/modules/1plusXRtdProvider.js +++ b/modules/1plusXRtdProvider.js @@ -1,10 +1,9 @@ import { submodule } from '../src/hook.js'; -import { config } from '../src/config.js'; import { ajax } from '../src/ajax.js'; import { logMessage, logError, - deepAccess, mergeDeep, - isNumber, isArray, deepSetValue + deepAccess, deepSetValue, mergeDeep, + isNumber, isArray, } from '../src/utils.js'; // Constants @@ -14,7 +13,6 @@ const ORTB2_NAME = '1plusX.com' const PAPI_VERSION = 'v1.0'; const LOG_PREFIX = '[1plusX RTD Module]: '; const OPE_FPID = 'ope_fpid' -const LEGACY_SITE_KEYWORDS_BIDDERS = ['appnexus']; export const segtaxes = { // cf. https://github.com/InteractiveAdvertisingBureau/openrtb/pull/108 AUDIENCE: 526, @@ -151,18 +149,7 @@ const getTargetingDataFromPapi = (papiUrl) => { * @param {string[]} topics Represents the topics of the page * @returns {Object} Object describing the updates to make on bidder configs */ -export const buildOrtb2Updates = ({ segments = [], topics = [] }, bidder) => { - // Currently appnexus bidAdapter doesn't support topics in `site.content.data.segment` - // Therefore, writing them in `site.keywords` until it's supported - // Other bidAdapters do fine with `site.content.data.segment` - const writeToLegacySiteKeywords = LEGACY_SITE_KEYWORDS_BIDDERS.includes(bidder); - if (writeToLegacySiteKeywords) { - const site = { - keywords: topics.join(',') - }; - return { site }; - } - +export const buildOrtb2Updates = ({ segments = [], topics = [] }) => { const userData = { name: ORTB2_NAME, segment: segments.map((segmentId) => ({ id: segmentId })) @@ -172,81 +159,64 @@ export const buildOrtb2Updates = ({ segments = [], topics = [] }, bidder) => { segment: topics.map((topicId) => ({ id: topicId })), ext: { segtax: segtaxes.CONTENT } } - return { userData, siteContentData }; + // Currently appnexus bidAdapter doesn't support topics in `site.content.data.segment` + // Therefore, writing them in `site.keywords` until it's supported + // Other bidAdapters do fine with `site.content.data.segment` + const siteKeywords = topics.map(topic => `1plusX=${topic}`).join(','); + + return { userData, siteContentData, siteKeywords }; } /** * Merges the targeting data with the existing config for bidder and updates * @param {string} bidder Bidder for which to set config * @param {Object} ortb2Updates Updates to be applied to bidder config - * @param {Object} bidderConfigs All current bidder configs - * @returns {Object} Updated bidder config + * @param {Object} biddersOrtb2 All current bidder configs */ -export const updateBidderConfig = (bidder, ortb2Updates, bidderConfigs) => { - const { site, siteContentData, userData } = ortb2Updates; - const bidderConfigCopy = mergeDeep({}, bidderConfigs[bidder]); +export const updateBidderConfig = (bidder, ortb2Updates, biddersOrtb2) => { + const { siteKeywords, siteContentData, userData } = ortb2Updates; + mergeDeep(biddersOrtb2, { [bidder]: {} }); + const bidderConfig = deepAccess(biddersOrtb2, bidder); - if (site) { - // Legacy : cf. comment on buildOrtb2Updates first lines - const currentSite = deepAccess(bidderConfigCopy, 'ortb2.site'); - const updatedSite = mergeDeep(currentSite, site); - deepSetValue(bidderConfigCopy, 'ortb2.site', updatedSite); + { + // Legacy : cf. comment on buildOrtb2Updates + const siteKeywordsPath = 'site.keywords'; + deepSetValue(bidderConfig, siteKeywordsPath, siteKeywords); } - if (siteContentData) { - const siteDataPath = 'ortb2.site.content.data'; - const currentSiteContentData = deepAccess(bidderConfigCopy, siteDataPath) || []; + { + const siteDataPath = 'site.content.data'; + const currentSiteContentData = deepAccess(bidderConfig, siteDataPath) || []; const updatedSiteContentData = [ ...currentSiteContentData.filter(({ name }) => name != siteContentData.name), siteContentData ]; - deepSetValue(bidderConfigCopy, siteDataPath, updatedSiteContentData); + deepSetValue(bidderConfig, siteDataPath, updatedSiteContentData); } - if (userData) { - const userDataPath = 'ortb2.user.data'; - const currentUserData = deepAccess(bidderConfigCopy, userDataPath) || []; + { + const userDataPath = 'user.data'; + const currentUserData = deepAccess(bidderConfig, userDataPath) || []; const updatedUserData = [ ...currentUserData.filter(({ name }) => name != userData.name), userData ]; - deepSetValue(bidderConfigCopy, userDataPath, updatedUserData); + deepSetValue(bidderConfig, userDataPath, updatedUserData); } - - return bidderConfigCopy; }; -const setAppnexusAudiences = (audiences) => { - config.setConfig({ - appnexusAuctionKeywords: { - '1plusX': audiences, - }, - }); -} - /** * Updates bidder configs with the targeting data retreived from Profile API * @param {Object} papiResponse Response from Profile API * @param {Object} config Module configuration * @param {string[]} config.bidders Bidders specified in module's configuration */ -export const setTargetingDataToConfig = (papiResponse, { bidders }) => { - const bidderConfigs = config.getBidderConfig(); +export const setTargetingDataToConfig = (papiResponse, { bidders, biddersOrtb2 }) => { const { s: segments, t: topics } = papiResponse; + const ortb2Updates = buildOrtb2Updates({ segments, topics }); for (const bidder of bidders) { - const ortb2Updates = buildOrtb2Updates({ segments, topics }, bidder); - const updatedBidderConfig = updateBidderConfig(bidder, ortb2Updates, bidderConfigs); - if (updatedBidderConfig) { - config.setBidderConfig({ - bidders: [bidder], - config: updatedBidderConfig - }); - } - if (bidder === 'appnexus') { - // Do the legacy stuff for appnexus with segments - setAppnexusAudiences(segments); - } + updateBidderConfig(bidder, ortb2Updates, biddersOrtb2); } } @@ -272,13 +242,14 @@ const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, userConsent try { // Get the required config const { customerId, bidders } = extractConfig(moduleConfig, reqBidsConfigObj); + const { ortb2Fragments: { bidder: biddersOrtb2 } } = reqBidsConfigObj; // Get PAPI URL const papiUrl = getPapiUrl(customerId, extractConsent(userConsent) || {}, extractFpid()) // Call PAPI getTargetingDataFromPapi(papiUrl) .then((papiResponse) => { logMessage(LOG_PREFIX, 'Get targeting data request successful'); - setTargetingDataToConfig(papiResponse, { bidders }); + setTargetingDataToConfig(papiResponse, { bidders, biddersOrtb2 }); callback(); }) } catch (error) { diff --git a/modules/adhashBidAdapter.js b/modules/adhashBidAdapter.js index 08f9466823b..96e93883de6 100644 --- a/modules/adhashBidAdapter.js +++ b/modules/adhashBidAdapter.js @@ -1,9 +1,9 @@ -import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; import { includes } from '../src/polyfill.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -const VERSION = '3.2'; +const VERSION = '3.6'; const BAD_WORD_STEP = 0.1; const BAD_WORD_MIN = 0.2; const ADHASH_BIDDER_CODE = 'adhash'; @@ -19,6 +19,8 @@ const ADHASH_BIDDER_CODE = 'adhash'; * @returns boolean flag is the page safe */ function brandSafety(badWords, maxScore) { + const delimiter = '~'; + /** * Performs the ROT13 encoding on the string argument and returns the resulting string. * The Adhash bidder uses ROT13 so that the response is not blocked by: @@ -40,17 +42,17 @@ function brandSafety(badWords, maxScore) { /** * Calculates the scoring for each bad word with dimishing returns * @param {integer} points points that this word costs - * @param {integer} occurances number of occurances + * @param {integer} occurrences number of occurrences * @returns {float} final score */ - const scoreCalculator = (points, occurances) => { + const scoreCalculator = (points, occurrences) => { let positive = true; if (points < 0) { points *= -1; positive = false; } let result = 0; - for (let i = 0; i < occurances; i++) { + for (let i = 0; i < occurrences; i++) { result += Math.max(points - i * BAD_WORD_STEP, BAD_WORD_MIN); } return positive ? result : -result; @@ -60,22 +62,50 @@ function brandSafety(badWords, maxScore) { * Checks what rule will match in the given array with words * @param {string} rule rule type (full, partial, starts, ends, regexp) * @param {string} decodedWord decoded word - * @param {array} wordsToMatch array to find a match + * @param {string} wordsToMatch list of all words on the page separated by delimiters * @returns {object|boolean} matched rule and occurances. If nothing is matched returns false */ const wordsMatchedWithRule = function (rule, decodedWord, wordsToMatch) { - if (rule === 'full' && wordsToMatch && wordsToMatch.includes(decodedWord)) { - return { rule, occurances: wordsToMatch.filter(element => element === decodedWord).length }; - } else if (rule === 'partial' && wordsToMatch && wordsToMatch.some(element => element.indexOf(decodedWord) > -1)) { - return { rule, occurances: wordsToMatch.filter(element => element.indexOf(decodedWord) > -1).length }; - } else if (rule === 'starts' && wordsToMatch && wordsToMatch.some(word => word.startsWith(decodedWord))) { - return { rule, occurances: wordsToMatch.filter(element => element.startsWith(decodedWord)).length }; - } else if (rule === 'ends' && wordsToMatch && wordsToMatch.some(word => word.endsWith(decodedWord))) { - return { rule, occurances: wordsToMatch.filter(element => element.endsWith(decodedWord)).length }; - } else if (rule === 'regexp' && wordsToMatch && wordsToMatch.some(element => element.match(new RegExp(decodedWord, 'i')))) { - return { rule, occurances: wordsToMatch.filter(element => element.match(new RegExp(decodedWord, 'i'))).length }; + if (!wordsToMatch) { + return false; + } + + let occurrences; + let adjustedWordToMatch; + decodedWord = decodedWord.split(' ').join(`${delimiter}${delimiter}`); + switch (rule) { + case 'full': + adjustedWordToMatch = `${delimiter}${decodedWord}${delimiter}`; + break; + case 'partial': + adjustedWordToMatch = decodedWord; + break; + case 'starts': + adjustedWordToMatch = `${delimiter}${decodedWord}`; + break; + case 'ends': + adjustedWordToMatch = `${decodedWord}${delimiter}`; + break; + case 'combo': + const allOccurrences = []; + const paddedWordsToMatch = `${delimiter}${wordsToMatch}${delimiter}`; + const decodedWordsSplit = decodedWord.split(`${delimiter}${delimiter}`); + for (const decodedWordPart of decodedWordsSplit) { + adjustedWordToMatch = `${delimiter}${decodedWordPart}${delimiter}`; + allOccurrences.push(paddedWordsToMatch.split(adjustedWordToMatch).length - 1); + } + occurrences = Math.min(...allOccurrences); + return occurrences > 0 ? { rule, occurrences } : false; + case 'regexp': + occurrences = [...wordsToMatch.matchAll(new RegExp(decodedWord, 'gi'))].length; + return occurrences > 0 ? { rule, occurrences } : false; + default: + return false; } - return false; + + const paddedWordsToMatch = `${delimiter}${wordsToMatch}${delimiter}`; + occurrences = paddedWordsToMatch.split(adjustedWordToMatch).length - 1; + return occurrences > 0 ? { rule, occurrences } : false; }; // Default parameters if the bidder is unable to send some of them @@ -91,11 +121,11 @@ function brandSafety(badWords, maxScore) { .toLowerCase() .trim(); const content = window.top.document.body.innerText.toLowerCase(); - const contentWords = content.trim().split(/\s+/).length; // \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language. const regexp = new RegExp('[\\p{L}]+', 'gu'); - const words = content.match(regexp); - const wordsInUrl = wordsAndNumbersInUrl.match(regexp); + const wordsMatched = content.match(regexp); + const words = wordsMatched.join(`${delimiter}${delimiter}`); + const wordsInUrl = wordsAndNumbersInUrl.match(regexp).join(`${delimiter}${delimiter}`); for (const [word, rule, points] of badWords) { const decodedWord = rot13(word.toLowerCase()); @@ -110,19 +140,11 @@ function brandSafety(badWords, maxScore) { // Check if site content's words match any of our brand safety rules const matchedRule = wordsMatchedWithRule(rule, decodedWord, words); - if (matchedRule.rule === 'full') { - score += scoreCalculator(points, matchedRule.occurances); - } else if (matchedRule.rule === 'partial') { - score += scoreCalculator(points, matchedRule.occurances); - } else if (matchedRule.rule === 'starts') { - score += scoreCalculator(points, matchedRule.occurances); - } else if (matchedRule.rule === 'ends') { - score += scoreCalculator(points, matchedRule.occurances); - } else if (matchedRule.rule === 'regexp') { - score += scoreCalculator(points, matchedRule.occurances); + if (matchedRule !== false) { + score += scoreCalculator(points, matchedRule.occurrences); } } - return score < (maxScore * contentWords) / 1000; + return score < (maxScore * wordsMatched.length) / 1000; } catch (e) { return true; } @@ -183,8 +205,8 @@ export const spec = { } // Needed for the ad density calculation - var adHeight = validBidRequests[i].sizes[index][1]; - var adWidth = validBidRequests[i].sizes[index][0]; + const adHeight = validBidRequests[i].sizes[index][1]; + const adWidth = validBidRequests[i].sizes[index][0]; if (!window.adsCount) { window.adsCount = 0; } @@ -247,7 +269,7 @@ export const spec = { const bidderResponse = JSON.stringify({ responseText: JSON.stringify(responseBody) }); const requestData = JSON.stringify(request.data); - var response = { + let response = { requestId: request.bidRequest.bidId, cpm: responseBody.creatives[0].costEUR, width: request.bidRequest.sizes[0][0], diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index 1217cfc0f2c..64567832dbd 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -90,7 +90,6 @@ export const spec = { {code: 'denakop'}, {code: 'rtbanalytica'}, {code: 'unibots'}, - {code: 'catapultx'}, {code: 'ergadx'}, {code: 'turktelekom'}, {code: 'felixads'}, @@ -100,7 +99,8 @@ export const spec = { {code: 'rtbdemand_com'}, {code: 'bidbuddy'}, {code: 'adliveconnect'}, - {code: 'didnadisplay'} + {code: 'didnadisplay'}, + {code: 'qortex'} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], diff --git a/modules/asoBidAdapter.js b/modules/asoBidAdapter.js index d8700ac6c6c..e569f04a2a8 100644 --- a/modules/asoBidAdapter.js +++ b/modules/asoBidAdapter.js @@ -28,7 +28,8 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], aliases: [ - {code: 'bcmint'} + {code: 'bcmint'}, + {code: 'bidgency'} ], isBidRequestValid: bid => { diff --git a/modules/beopBidAdapter.js b/modules/beopBidAdapter.js index 0b3c6d9cae8..6348854ec2a 100644 --- a/modules/beopBidAdapter.js +++ b/modules/beopBidAdapter.js @@ -48,6 +48,8 @@ export const spec = { */ buildRequests: function(validBidRequests, bidderRequest) { const slots = validBidRequests.map(beOpRequestSlotsMaker); + const firstPartyData = bidderRequest.ortb2; + const psegs = (firstPartyData && firstPartyData.user && firstPartyData.user.ext && firstPartyData.user.ext.data) ? firstPartyData.user.ext.data.permutive : undefined; const pageUrl = getPageUrl(bidderRequest.refererInfo, window); const gdpr = bidderRequest.gdprConsent; const firstSlot = slots[0]; @@ -69,6 +71,10 @@ export const spec = { tc_string: (gdpr && gdpr.gdprApplies) ? gdpr.consentString : null, }; + if (psegs) { + Object.assign(payloadObject, {psegs: psegs}); + } + const payloadString = JSON.stringify(payloadObject); return { method: 'POST', diff --git a/modules/conceptxBidAdapter.js b/modules/conceptxBidAdapter.js new file mode 100644 index 00000000000..1147a50e71f --- /dev/null +++ b/modules/conceptxBidAdapter.js @@ -0,0 +1,70 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +// import { logError, logInfo, logWarn, parseUrl } from '../src/utils.js'; + +const BIDDER_CODE = 'conceptx'; +let ENDPOINT_URL = 'https://conceptx.cncpt-central.com/openrtb'; +// const LOG_PREFIX = 'ConceptX: '; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + isBidRequestValid: function (bid) { + return !!(bid.bidId); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + // logWarn(LOG_PREFIX + 'all native assets containing URL should be sent as placeholders with sendId(icon, image, clickUrl, displayUrl, privacyLink, privacyIcon)'); + const requests = []; + + if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { + ENDPOINT_URL += '?gdpr_applies=' + bidderRequest.gdprConsent.gdprApplies; + ENDPOINT_URL += '&consentString=' + bidderRequest.gdprConsent.consentString; + } + for (var i = 0; i < validBidRequests.length; i++) { + const requestParent = { adUnits: [], meta: {} }; + const bid = validBidRequests[i] + const { adUnitCode, auctionId, bidId, bidder, bidderRequestId, ortb2 } = bid + requestParent.meta = { adUnitCode, auctionId, bidId, bidder, bidderRequestId, ortb2 } + + const { site, adunit } = bid.params + const adUnit = { site, adunit, targetId: bid.bidId } + if (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) adUnit.dimensions = bid.mediaTypes.banner.sizes + requestParent.adUnits.push(adUnit); + requests.push({ + method: 'POST', + url: ENDPOINT_URL, + options: { + withCredentials: false, + }, + data: JSON.stringify(requestParent), + }); + } + + return requests; + }, + + interpretResponse: function (serverResponse, bidRequest) { + const bidResponsesFromServer = serverResponse.body.bidResponses; + const firstDummy = bidResponsesFromServer[0] + const firstSeat = firstDummy.ads[0] + const bidResponses = []; + const bidResponse = { + requestId: firstSeat.requestId, + cpm: firstSeat.cpm, + width: firstSeat.width, + height: firstSeat.height, + creativeId: firstSeat.creativeId, + dealId: firstSeat.dealId, + currency: firstSeat.currency, + netRevenue: true, + ttl: firstSeat.ttl, + referrer: firstSeat.referrer, + ad: firstSeat.html + }; + bidResponses.push(bidResponse); + return bidResponses; + }, + +} +registerBidder(spec); diff --git a/modules/conceptxBidAdapter.md b/modules/conceptxBidAdapter.md new file mode 100644 index 00000000000..1464c04025a --- /dev/null +++ b/modules/conceptxBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: ConceptX Bidder Adapter +Module Type: Bidder Adapter +Maintainer: info@concept.dk +``` + +# Description + +ConceptX Bidder Adapter for Prebid.js. +Only Banner format is supported. + +# Test Parameters +``` + var adUnits = [ + { + code: "test-div", + mediaTypes: { + banner: { + sizes: [[980, 180]] + } + }, + bids: [ + { + bidder: "conceptx", + params: { + site: "example", + adunit: "some-id-3", + } + }, + ] + }, + + ]; +``` diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 6488ccb746e..993346df849 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -177,7 +177,14 @@ export const spec = { if (publisherTagAvailable()) { // eslint-disable-next-line no-undef - const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$'); + const adapter = new Criteo.PubTag.Adapters.Prebid( + PROFILE_ID_PUBLISHERTAG, + ADAPTER_VERSION, + bidRequests, + bidderRequest, + '$prebid.version$', + { createOutstreamVideoRenderer: createOutstreamVideoRenderer } + ); url = adapter.buildCdbUrl(); data = adapter.buildCdbRequest(); } else { diff --git a/modules/freepassIdSystem.js b/modules/freepassIdSystem.js new file mode 100644 index 00000000000..d52c537e800 --- /dev/null +++ b/modules/freepassIdSystem.js @@ -0,0 +1,61 @@ +import { submodule } from '../src/hook.js'; +import {generateUUID, logMessage} from '../src/utils.js'; + +const MODULE_NAME = 'freepassId'; + +export const freepassIdSubmodule = { + name: MODULE_NAME, + decode: function (value, config) { + logMessage('Decoding FreePass ID: ', value); + + return { [MODULE_NAME]: value }; + }, + + getId: function (config, consent, cachedIdObject) { + logMessage('Getting FreePass ID using config: ' + JSON.stringify(config)); + + const freepassData = config.params !== undefined ? (config.params.freepassData || {}) : {} + let idObject = {userId: generateUUID()}; + + if (freepassData.commonId !== undefined) { + idObject.commonId = config.params.freepassData.commonId; + } + + if (freepassData.userIp !== undefined) { + idObject.userIp = config.params.freepassData.userIp; + } + + return {id: idObject}; + }, + + extendId: function (config, consent, cachedIdObject) { + let freepassData = config.params.freepassData; + let hasFreepassData = freepassData !== undefined; + if (!hasFreepassData) { + logMessage('No Freepass Data. CachedIdObject will not be extended: ' + JSON.stringify(cachedIdObject)); + return { + id: cachedIdObject + }; + } + + if (freepassData.commonId === cachedIdObject.commonId && freepassData.userIp === cachedIdObject.userIp) { + logMessage('FreePass ID is already up-to-date: ' + JSON.stringify(cachedIdObject)); + return { + id: cachedIdObject + }; + } + + logMessage('Extending FreePass ID object: ' + JSON.stringify(cachedIdObject)); + logMessage('Extending FreePass ID using config: ' + JSON.stringify(config)); + + return { + id: { + commonId: freepassData.commonId, + userIp: freepassData.userIp, + userId: cachedIdObject.userId, + }, + }; + } +}; + +submodule('userId', freepassIdSubmodule); diff --git a/modules/freepassIdSystem.md b/modules/freepassIdSystem.md new file mode 100644 index 00000000000..de0cdf23f68 --- /dev/null +++ b/modules/freepassIdSystem.md @@ -0,0 +1,47 @@ +## FreePass User ID Submodule + +[FreePass](https://freepass-login.com/introduction.html) is a common authentication service operated by Freebit Co., Ltd. Users with a FreePass account do not need to create a new account to use partner services. + +# General Information + +Please contact FreePass before using this ID. + +``` +Module Name: FreePass Id System +Module Type: User Id System +Maintainer: freepass-headerbidding@craid-inc.com +``` + +## Building Prebid with FreePass ID Support + +First, make sure to add the FreePass ID submodule to your Prebid.js package with: + +```shell +gulp build --modules=freepassIdSystem,userId +``` + +The following configuration parameters are available: + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'freepassId', + params: { + freepassData: { + commonId: 'fpcommonid123', + userIp: '127.0.0.1' + } + } + }] + } +}); +``` + +| Param under userSync.userIds[] | Scope | Type | Description | Example | +|--------------------------------|----------|--------|------------------------------------------------------|----------------| +| name | Required | String | The name of this module | `"freepassId"` | +| freepassData | Optional | Object | FreePass data | `{}` | +| freepassData.commonId | Optional | String | Common ID obtained from FreePass | `"abcd1234"` | +| freepassData.userIp | Optional | String | User IP obtained in cooperation with partner service | `"127.0.0.1"` | + diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 1f7f203df8e..000131d9e03 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -96,7 +96,7 @@ const VIDEO_PARAMS_ALLOW_LIST = [ 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext', - 'playerSize', 'w', 'h' + 'playerSize', 'w', 'h', 'plcmt' ]; const LOCAL_STORAGE_KEY = 'ixdiag'; export const LOCAL_STORAGE_FEATURE_TOGGLES_KEY = `${BIDDER_CODE}_features`; @@ -216,6 +216,8 @@ function bidToVideoImp(bid) { const context = (videoParamRef && videoParamRef.context) || (videoAdUnitRef && videoAdUnitRef.context); + verifyVideoPlcmt(imp); + // if placement not already defined, pick one based on `context` if (context && !imp.video.hasOwnProperty('placement')) { if (context === INSTREAM) { @@ -249,6 +251,15 @@ function bidToVideoImp(bid) { return imp; } +function verifyVideoPlcmt(imp) { + if (imp.video.hasOwnProperty('plcmt') && (!isInteger(imp.video.plcmt) || (imp.video.plcmt < 1 || imp.video.plcmt > 4))) { + logWarn( + `IX Bid Adapter: video.plcmt [${imp.video.plcmt}] must be an integer between 1-4 inclusive` + ); + delete imp.video.plcmt; + } +} + /** * Transform valid bid request config object to native impression object that will be sent to ad server. * diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index c7fbc13a8e1..0eb9e900160 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -26,7 +26,7 @@ function isBidResponseValid(bid) { export const spec = { code: BIDDER_CODE, - aliases: ['pll', 'iionads'], + aliases: ['pll', 'iionads', 'apester'], supportedMediaTypes: [BANNER, VIDEO], /** diff --git a/modules/mediasquareBidAdapter.js b/modules/mediasquareBidAdapter.js index 274cbadca06..720063253de 100644 --- a/modules/mediasquareBidAdapter.js +++ b/modules/mediasquareBidAdapter.js @@ -128,6 +128,9 @@ export const spec = { 'advertiserDomains': value['adomain'] } }; + if ('context' in value) { + bidResponse['mediasquare']['context'] = value['context']; + } if ('match' in value) { bidResponse['mediasquare']['match'] = value['match']; } @@ -172,15 +175,20 @@ export const spec = { */ onBidWon: function(bid) { // fires a pixel to confirm a winning bid + if (bid.hasOwnProperty('mediaType') && bid.mediaType == 'video') { + return; + } let params = { pbjs: '$prebid.version$', referer: encodeURIComponent(getRefererInfo().page || getRefererInfo().topmostLocation) }; let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD; - let paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond', 'requestId', 'auctionId', 'originalCpm', 'originalCurrency']; + let paramsToSearchFor = ['bidder', 'code', 'match', 'hasConsent', 'context']; if (bid.hasOwnProperty('mediasquare')) { - if (bid['mediasquare'].hasOwnProperty('bidder')) { params['bidder'] = bid['mediasquare']['bidder']; } - if (bid['mediasquare'].hasOwnProperty('code')) { params['code'] = bid['mediasquare']['code']; } - if (bid['mediasquare'].hasOwnProperty('match')) { params['match'] = bid['mediasquare']['match']; } - if (bid['mediasquare'].hasOwnProperty('hasConsent')) { params['hasConsent'] = bid['mediasquare']['hasConsent']; } + for (let i = 0; i < paramsToSearchFor.length; i++) { + if (bid['mediasquare'].hasOwnProperty(paramsToSearchFor[i])) { + params[paramsToSearchFor[i]] = bid['mediasquare'][paramsToSearchFor[i]]; + } + } }; + paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond', 'requestId', 'auctionId', 'originalCpm', 'originalCurrency']; for (let i = 0; i < paramsToSearchFor.length; i++) { if (bid.hasOwnProperty(paramsToSearchFor[i])) { params[paramsToSearchFor[i]] = bid[paramsToSearchFor[i]]; diff --git a/modules/proxistoreBidAdapter.js b/modules/proxistoreBidAdapter.js index d7661acda07..f3fb662ba06 100644 --- a/modules/proxistoreBidAdapter.js +++ b/modules/proxistoreBidAdapter.js @@ -89,23 +89,20 @@ function _createServerRequest(bidRequests, bidderRequest) { } function _assignSegments(bid) { - if ( - bid.ortb2 && - bid.ortb2.user && - bid.ortb2.user.ext && - bid.ortb2.user.ext.data - ) { - return ( - bid.ortb2.user.ext.data || { - segments: [], - contextual_categories: {}, - } - ); + var segs = (bid.ortb2 && bid.ortb2.user && bid.ortb2.user.ext && bid.ortb2.user.ext.data && bid.ortb2.user.ext.data.sd_rtd && bid.ortb2.user.ext.data.sd_rtd.segments ? bid.ortb2.user.ext.data.sd_rtd.segments : []); + var cats = {}; + if (bid.ortb2 && bid.ortb2.site && bid.ortb2.site.ext && bid.ortb2.site.ext.data && bid.ortb2.site.ext.data.sd_rtd) { + if (bid.ortb2.site.ext.data.sd_rtd.categories) { + segs = segs.concat(bid.ortb2.site.ext.data.sd_rtd.categories); + } + if (bid.ortb2.site.ext.data.sd_rtd.categories_score) { + cats = bid.ortb2.site.ext.data.sd_rtd.categories_score; + } } return { - segments: [], - contextual_categories: {}, + segments: segs, + contextual_categories: cats }; } diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 40ee3d8b973..aaa3c48856b 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -134,44 +134,24 @@ export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, }); } -export function setGlobalOrtb2Sda(ortb2Fragments, data, segtaxid, cattaxid) { +export function pushToOrtb2(ortb2Fragments, bidder, data, segtaxid, cattaxid) { try { if (!isEmpty(data.segments)) { - applyGlobalOrtb2Sda(ortb2Fragments, 'user', data.segments, segtaxid); + if (segtaxid) { + setOrtb2Sda(ortb2Fragments, bidder, 'user', data.segments, segtaxid); + } else { + setOrtb2(ortb2Fragments, bidder, 'user.ext.data', {sd_rtd: {segments: data.segments}}); + } } if (!isEmpty(data.categories)) { - applyGlobalOrtb2Sda(ortb2Fragments, 'site', data.categories, cattaxid); - } - } catch (e) { - logError(e) - } - return true; -} - -export function applyGlobalOrtb2Sda(ortb2Fragments, type, segments, segtaxValue) { - try { - let ortb2Data = [{ - name: ORTB2_NAME, - segment: segments.map((segmentId) => ({ id: segmentId })), - }]; - if (segtaxValue) { - ortb2Data[0].ext = { segtax: segtaxValue }; - } - let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); - mergeDeep(ortb2Fragments, ortb2Conf); - } catch (e) { - logError(e) - } - return true; -} - -export function setBidderOrtb2Sda(ortb2Fragments, bidder, data, segtaxid, cattaxid) { - try { - if (!isEmpty(data.segments)) { - applyBidderOrtb2Sda(ortb2Fragments, bidder, 'user', data.segments, segtaxid); + if (cattaxid) { + setOrtb2Sda(ortb2Fragments, bidder, 'site', data.categories, cattaxid); + } else { + setOrtb2(ortb2Fragments, bidder, 'site.ext.data', {sd_rtd: {categories: data.categories}}); + } } - if (!isEmpty(data.categories)) { - applyBidderOrtb2Sda(ortb2Fragments, bidder, 'site', data.categories, cattaxid); + if (!isEmpty(data.categories_score) && !cattaxid) { + setOrtb2(ortb2Fragments, bidder, 'site.ext.data', {sd_rtd: {categories_score: data.categories_score}}); } } catch (e) { logError(e) @@ -179,7 +159,7 @@ export function setBidderOrtb2Sda(ortb2Fragments, bidder, data, segtaxid, cattax return true; } -export function applyBidderOrtb2Sda(ortb2Fragments, bidder, type, segments, segtaxValue) { +export function setOrtb2Sda(ortb2Fragments, bidder, type, segments, segtaxValue) { try { let ortb2Data = [{ name: ORTB2_NAME, @@ -189,19 +169,25 @@ export function applyBidderOrtb2Sda(ortb2Fragments, bidder, type, segments, segt ortb2Data[0].ext = { segtax: segtaxValue }; } let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); - mergeDeep(ortb2Fragments, {[bidder]: ortb2Conf}); + if (bidder) { + ortb2Conf = {[bidder]: ortb2Conf}; + } + mergeDeep(ortb2Fragments, ortb2Conf); } catch (e) { logError(e) } return true; } -export function setBidderOrtb2(bidderOrtb2Fragments, bidder, path, segments) { +export function setOrtb2(ortb2Fragments, bidder, path, segments) { try { - if (isEmpty(segments)) { return; } + if (isEmpty(segments)) { return false; } let ortb2Conf = {}; deepSetValue(ortb2Conf, path, segments || {}); - mergeDeep(bidderOrtb2Fragments, {[bidder]: ortb2Conf}); + if (bidder) { + ortb2Conf = {[bidder]: ortb2Conf}; + } + mergeDeep(ortb2Fragments, ortb2Conf); } catch (e) { logError(e) } @@ -221,15 +207,22 @@ export function loadCustomFunction(todo, adUnit, list, data, bid) { } export function getSegAndCatsArray(data, minScore, pid) { - let sirdataData = {'segments': [], 'categories': []}; + let sirdataData = {'segments': [], 'categories': [], 'categories_score': {}}; minScore = minScore && typeof minScore == 'number' ? minScore : 30; + let cattaxid = data.cattaxid || null; + let segtaxid = data.segtaxid || null; try { if (data && data.contextual_categories) { for (let catId in data.contextual_categories) { if (data.contextual_categories.hasOwnProperty(catId) && data.contextual_categories[catId]) { let value = data.contextual_categories[catId]; if (value >= minScore && sirdataData.categories.indexOf(catId) === -1) { - sirdataData.categories.push((pid ? pid.toString() + 'cc' : '') + catId.toString()); + if (pid && cattaxid) { + sirdataData.categories.push(pid.toString() + 'cc' + catId.toString()); + } else { + sirdataData.categories.push(catId.toString()); + sirdataData.categories_score[catId] = value; + } } } } @@ -241,9 +234,16 @@ export function getSegAndCatsArray(data, minScore, pid) { if (data && data.segments) { for (let segId in data.segments) { if (data.segments.hasOwnProperty(segId) && data.segments[segId]) { - sirdataData.segments.push((pid ? pid.toString() + 'us' : '') + data.segments[segId].toString()); + let id = data.segments[segId].toString(); if (pid && CONTEXT_ONLY) { - sirdataData.categories.push(pid.toString() + 'uc' + data.segments[segId].toString()); + if (segtaxid) { + sirdataData.categories.push(pid.toString() + 'uc' + id); + } else { + sirdataData.categories.push(id); + sirdataData.categories_score[id] = 100; + } + } else { + sirdataData.segments.push((pid && segtaxid) ? pid.toString() + 'us' + id : id); } } } @@ -254,12 +254,12 @@ export function getSegAndCatsArray(data, minScore, pid) { return sirdataData; } -export function applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { +export function applySdaGetSpecificData(data, sirdataData, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { // only share SDA data if whitelisted if (!biddersParamsExist || indexFound) { // SDA Publisher let sirdataDataForSDA = getSegAndCatsArray(data, minScore, moduleConfig.params.partnerId); - setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, sirdataDataForSDA, data.segtaxid, data.cattaxid); + pushToOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, sirdataDataForSDA, data.segtaxid, data.cattaxid); } // always share SDA for curation @@ -268,30 +268,31 @@ export function applySdaGetSpecificData(data, sirdataList, biddersParamsExist, m // seller defined audience & bidder specific data if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { // Get Bidder Specific Data - let curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, null); - sirdataList = sirdataList.concat(curationData.segments).concat(curationData.categories); - - // SDA Partners - let curationDataForSDA = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, curationId); - setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, curationDataForSDA, data.shared_taxonomy[curationId].segtaxid, data.shared_taxonomy[curationId].cattaxid); + let curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, curationId); + pushToOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, curationData, data.shared_taxonomy[curationId].segtaxid, data.shared_taxonomy[curationId].cattaxid); } } // Apply custom function or return Bidder Specific Data if publisher is ok - if (sirdataList && sirdataList.length > 0 && (!biddersParamsExist || indexFound)) { + if (!biddersParamsExist || indexFound) { if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - return loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataList, data, bid); + return loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataData, data, bid); } else { - return sirdataList; + return sirdataData; } } } -export function applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { - let specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - if (specificData && specificData.length > 0) { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', {sd_rtd: specificData}); +export function applySdaAndDefaultSpecificData(data, sirdataData, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { + sirdataData = applySdaGetSpecificData(data, sirdataData, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + /* + if (sirdataData.segments && sirdataData.segments.length > 0) { + setOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', {sd_rtd: sirdataData.segments}); } + if (sirdataData.categories && sirdataData.categories.length > 0) { + setOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'site.ext.data', {sd_rtd: sirdataData.categories}); + } + */ } export function addSegmentData(reqBids, data, moduleConfig, onDone) { @@ -301,17 +302,15 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { const globalMinScore = moduleConfig.params.hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.contextualMinRelevancyScore : 30; var sirdataData = getSegAndCatsArray(data, globalMinScore, null); - const sirdataList = sirdataData.segments.concat(sirdataData.categories); - const biddersParamsExist = (!!(moduleConfig.params && moduleConfig.params.bidders)); // Global ortb2 SDA if (data.global_taxonomy && !isEmpty(data.global_taxonomy)) { - let globalData = {'segments': [], 'categories': []}; + let globalData = {'segments': [], 'categories': [], 'categories_score': []}; for (let i in data.global_taxonomy) { if (!isEmpty(data.global_taxonomy[i])) { globalData = getSegAndCatsArray(data.global_taxonomy[i], globalMinScore, null); - setGlobalOrtb2Sda(reqBids.ortb2Fragments?.global, globalData, data.global_taxonomy[i].segtaxid, data.global_taxonomy[i].cattaxid); + pushToOrtb2(reqBids.ortb2Fragments?.global, null, globalData, data.global_taxonomy[i].segtaxid, data.global_taxonomy[i].cattaxid); } } } @@ -320,15 +319,17 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { if (typeof window.googletag !== 'undefined' && (moduleConfig.params.setGptKeyValues || !moduleConfig.params.hasOwnProperty('setGptKeyValues'))) { try { let gptCurationId = (moduleConfig.params.gptCurationId ? moduleConfig.params.gptCurationId : (partnerIds['sdRtdForGpt'] ? partnerIds['sdRtdForGpt'] : null)); - let sirdataMergedList = sirdataList; + let sirdataMergedList = sirdataData.segments.concat(sirdataData.categories); if (gptCurationId && data.shared_taxonomy && data.shared_taxonomy[gptCurationId]) { let gamCurationData = getSegAndCatsArray(data.shared_taxonomy[gptCurationId], globalMinScore, null); sirdataMergedList = sirdataMergedList.concat(gamCurationData.segments).concat(gamCurationData.categories); } - window.googletag.pubads().getSlots().forEach(function (n) { - if (typeof n.setTargeting !== 'undefined' && sirdataMergedList && sirdataMergedList.length > 0) { - n.setTargeting('sd_rtd', sirdataMergedList); - } + window.googletag.cmd.push(function() { + window.googletag.pubads().getSlots().forEach(function (n) { + if (typeof n.setTargeting !== 'undefined' && sirdataMergedList && sirdataMergedList.length > 0) { + n.setTargeting('sd_rtd', sirdataMergedList); + } + }); }); } catch (e) { logError(e); @@ -340,10 +341,6 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { var indexFound = false; adUnits.forEach(adUnit => { - if (!biddersParamsExist && !deepAccess(adUnit, 'ortb2Imp.ext.data.sd_rtd')) { - deepSetValue(adUnit, 'ortb2Imp.ext.data.sd_rtd', sirdataList); - } - adUnit.hasOwnProperty('bids') && adUnit.bids.forEach(bid => { bidderIndex = (moduleConfig.params.hasOwnProperty('bidders') ? findIndex(moduleConfig.params.bidders, function (i) { return i.bidder === bid.bidder; @@ -351,7 +348,6 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { indexFound = (!!(typeof bidderIndex == 'number' && bidderIndex >= 0)); try { let minScore = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.bidders[bidderIndex].contextualMinRelevancyScore : globalMinScore); - let specificData = null; switch (bid.bidder) { case 'appnexus': @@ -370,87 +366,18 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { case 'msq_classic': case 'msq_max': case '366_apx': - specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - if (specificData && specificData.length > 0) { - deepSetValue(bid, 'params.keywords.sd_rtd', specificData); + sirdataData = applySdaGetSpecificData(data, sirdataData, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (sirdataData.segments && sirdataData.segments.length > 0) { + setOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.keywords', 'sd_rtd=' + sirdataData.segments.join(',sd_rtd=')); } - break; - - case 'smartadserver': - case 'smart': - specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - if (specificData && specificData.length > 0) { - var target = []; - if (bid.hasOwnProperty('params') && bid.params.hasOwnProperty('target')) { - target.push(bid.params.target); - } - specificData.forEach(function (entry) { - if (target.indexOf('sd_rtd=' + entry) === -1) { - target.push('sd_rtd=' + entry); - } - }); - deepSetValue(bid, 'params.target', target.join(';')); + if (sirdataData.categories && sirdataData.categories.length > 0) { + setOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'site.content.keywords', 'sd_rtd=' + sirdataData.categories.join(',sd_rtd=')); } break; - case 'ix': - specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - let ixConfig = config.getConfig('ix.firstPartyData.sd_rtd'); - if (!ixConfig && specificData && specificData.length > 0) { - let cappIxCategories = []; - let ixLength = 0; - let ixLimit = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('sizeLimit') ? moduleConfig.params.bidders[bidderIndex].sizeLimit : 1000); - // Push ids For publisher use and for curation if exists but limit size because the bidder uses GET parameters - specificData.forEach(function (entry) { - if (ixLength < ixLimit) { - cappIxCategories.push(entry); - ixLength += entry.toString().length; - } - }); - config.setConfig({ix: {firstPartyData: {sd_rtd: cappIxCategories}}}); - } - break; - - case 'proxistore': - specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - if (specificData && specificData.length > 0) { - let psCurationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : (partnerIds[bid.bidder] ? partnerIds[bid.bidder] : null)); - if (!data.shared_taxonomy || !data.shared_taxonomy[psCurationId]) { - data.shared_taxonomy[psCurationId] = {segments: [], contextual_categories: {}, segtaxid: null, cattaxid: null}; - } - let psCurationData = getSegAndCatsArray(data.shared_taxonomy[psCurationId], minScore, null); - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', { - segments: sirdataData.segments.concat(psCurationData.segments), - contextual_categories: {...data.contextual_categories, ...data.shared_taxonomy[psCurationId].contextual_categories} - }); - } - break; - - case 'rubicon': - case 'criteo': - case 'triplelift': - case 'smaato': - case 'yahoossp': - case 'openx': - case 'pubmatic': - case 'smilewanted': - case 'taboola': - case 'ttd': - case 'zeta_global': - case 'zeta_global_ssp': - case 'teads': - case 'conversant': - case 'improvedigital': - case 'invibes': - case 'sublime': - case 'rtbhouse': - case 'mediasquare': - applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); - break; - default: if (!biddersParamsExist || (indexFound && (!moduleConfig.params.bidders[bidderIndex].hasOwnProperty('adUnitCodes') || moduleConfig.params.bidders[bidderIndex].adUnitCodes.indexOf(adUnit.code) !== -1))) { - applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + applySdaAndDefaultSpecificData(data, sirdataData, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); } } } catch (e) { diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index b825a554e4d..f21c4d1752a 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -151,11 +151,14 @@ export const spec = { site.page = bidderRequest.refererInfo.page site.domain = bidderRequest.refererInfo.domain + const tmax = deepAccess(bidderRequest, 'timeout'); + const sovrnBidReq = { id: getUniqueIdentifierStr(), imp: sovrnImps, site: site, - user: fpd.user || {} + user: fpd.user || {}, + tmax: tmax } if (schain) { diff --git a/modules/stroeerCoreBidAdapter.js b/modules/stroeerCoreBidAdapter.js index 15c15a89609..0737bec5a12 100644 --- a/modules/stroeerCoreBidAdapter.js +++ b/modules/stroeerCoreBidAdapter.js @@ -1,6 +1,7 @@ import {buildUrl, deepAccess, getWindowSelf, getWindowTop, isEmpty, isStr, logWarn} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {find} from '../src/polyfill.js'; const GVL_ID = 136; const BIDDER_CODE = 'stroeerCore'; @@ -212,12 +213,16 @@ const mapToPayloadBaseBid = (bidRequest) => ({ viz: elementInView(bidRequest.adUnitCode), }); -const mapToPayloadBannerBid = (bidRequest) => ({ - ban: { - siz: deepAccess(bidRequest, 'mediaTypes.banner.sizes') || [], - }, - ...mapToPayloadBaseBid(bidRequest) -}); +const mapToPayloadBannerBid = (bidRequest) => { + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') || []; + return ({ + ban: { + siz: sizes, + fp: createFloorPriceObject(BANNER, sizes, bidRequest) + }, + ...mapToPayloadBaseBid(bidRequest) + }); +}; const mapToPayloadVideoBid = (bidRequest) => { const video = deepAccess(bidRequest, 'mediaTypes.video') || {}; @@ -226,9 +231,53 @@ const mapToPayloadVideoBid = (bidRequest) => { ctx: video.context, siz: video.playerSize, mim: video.mimes, + fp: createFloorPriceObject(VIDEO, [video.playerSize], bidRequest), }, ...mapToPayloadBaseBid(bidRequest) }; }; +const createFloorPriceObject = (mediaType, sizes, bidRequest) => { + if (!bidRequest.getFloor) { + return undefined; + } + + const defaultFloor = bidRequest.getFloor({ + currency: 'EUR', + mediaType: mediaType, + size: '*' + }); + + const sizeFloors = sizes.map(size => { + const floor = bidRequest.getFloor({ + currency: 'EUR', + mediaType: mediaType, + size: [size[0], size[1]] + }); + return {...floor, size}; + }); + + const floorWithCurrency = find([defaultFloor].concat(sizeFloors), floor => floor.currency); + + if (!floorWithCurrency) { + return undefined; + } + + const currency = floorWithCurrency.currency; + const defaultFloorPrice = defaultFloor.currency === currency ? defaultFloor.floor : undefined; + + return { + def: defaultFloorPrice, + cur: currency, + siz: sizeFloors + .filter(sizeFloor => sizeFloor.currency === currency) + .filter(sizeFloor => sizeFloor.floor !== defaultFloorPrice) + .map(sizeFloor => ({ + w: sizeFloor.size[0], + h: sizeFloor.size[1], + p: sizeFloor.floor + })) + }; +} + registerBidder(spec); diff --git a/modules/videojsVideoProvider.js b/modules/videojsVideoProvider.js index 96e5bc4311e..23a23447faa 100644 --- a/modules/videojsVideoProvider.js +++ b/modules/videojsVideoProvider.js @@ -628,6 +628,8 @@ export const utils = { return 'adserror'; case CONTENT_LOADED: return 'loadstart'; + case ERROR: + return ['error', 'aderror', 'contenterror']; case PLAY: return PLAY + 'ing'; case PLAYBACK_REQUEST: diff --git a/modules/viouslyBidAdapter.js b/modules/viouslyBidAdapter.js index 677838dae55..5ccca7590dd 100644 --- a/modules/viouslyBidAdapter.js +++ b/modules/viouslyBidAdapter.js @@ -5,7 +5,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js'; import find from 'core-js-pure/features/array/find.js'; // eslint-disable-line prebid/validate-imports const BIDDER_CODE = 'viously'; -// const GVLID = 1028; +const GVLID = 1028; const CURRENCY = 'EUR'; const TTL = 60; const HTTP_METHOD = 'POST'; @@ -15,7 +15,7 @@ const REQUIRED_VIOUSLY_PARAMS = ['pid']; export const spec = { code: BIDDER_CODE, - // gvlid: GVLID, + gvlid: GVLID, supportedMediaTypes: [BANNER, VIDEO], /** diff --git a/modules/weboramaRtdProvider.js b/modules/weboramaRtdProvider.js index 7e5b21de5a6..6ba502d2c8b 100644 --- a/modules/weboramaRtdProvider.js +++ b/modules/weboramaRtdProvider.js @@ -689,19 +689,8 @@ class WeboramaRtdProvider { /** @type {string} */ const bidder = bidderAliasRegistry[bid.bidder] || bid.bidder; - switch (bidder) { - case 'appnexus': - this.#handleAppnexusBid(bid, profile); - break; - case 'pubmatic': - this.#handlePubmaticBid(bid, profile); - break; - case 'smartadserver': - this.#handleSmartadserverBid(bid, profile); - break; - case 'rubicon': - this.#handleRubiconBid(bid, profile, metadata); - break; + if (bidder == 'appnexus') { + this.#handleAppnexusBid(reqBidsConfigObj, bid, profile); } } @@ -719,92 +708,19 @@ class WeboramaRtdProvider { /** handle appnexus/xandr bid * @method * @private + * @param {Object} reqBidsConfigObj + * @param {Object} reqBidsConfigObj.ortb2Fragments + * @param {Object} reqBidsConfigObj.ortb2Fragments.bidder * @param {Object} bid - * @param {Object} bid.params - * @param {Object} bid.params.keyword + * @param {Object} bid.parameters * @param {Profile} profile * @returns {void} */ // eslint-disable-next-line no-dupe-class-members - #handleAppnexusBid(bid, profile) { + #handleAppnexusBid(reqBidsConfigObj, bid, profile) { const base = 'params.keywords'; this.#assignProfileToObject(bid, base, profile); - } - - /** handle pubmatic bid - * @method - * @private - * @param {Object} bid - * @param {Object} bid.params - * @param {string} bid.params.dctr - * @param {Profile} profile - * @returns {void} - */ - // eslint-disable-next-line no-dupe-class-members - #handlePubmaticBid(bid, profile) { - const sep = '|'; - const subsep = ','; - - bid.params ||= {}; - - const data = bid.params.dctr || ''; - const target = new Set(data.split(sep).filter((x) => x.length > 0)); - - Object.entries(profile).forEach(([key, values]) => { - const value = values.join(subsep); - const keyword = `${key}=${value}`; - target.add(keyword); - }); - - bid.params.dctr = Array.from(target).join(sep); - } - - /** handle smartadserver bid - * @method - * @private - * @param {Object} bid - * @param {Object} bid.params - * @param {string} bid.params.target - * @param {Profile} profile - * @returns {void} - */ - // eslint-disable-next-line no-dupe-class-members - #handleSmartadserverBid(bid, profile) { - const sep = ';'; - - bid.params ||= {}; - - const data = bid.params.target || ''; - const target = new Set(data.split(sep).filter((x) => x.length > 0)); - - Object.entries(profile).forEach(([key, values]) => { - values.forEach(value => { - const keyword = `${key}=${value}`; - target.add(keyword); - }) - }); - - bid.params.target = Array.from(target).join(sep); - } - - /** handle rubicon bid - * @method - * @private - * @param {Object} bid - * @param {string} bid.bidder - * @param {Profile} profile - * @param {dataCallbackMetadata} metadata - * @returns {void} - */ - // eslint-disable-next-line no-dupe-class-members - #handleRubiconBid(bid, profile, metadata) { - if (isBoolean(metadata.user)) { - const section = metadata.user ? 'visitor' : 'inventory'; - const base = `params.${section}`; - this.#assignProfileToObject(bid, base, profile); - } else { - logMessage(`SKIP bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`); - } + // this.#setBidderOrtb2(reqBidsConfigObj.ortb2Fragments?.bidder, bid.bidder, base, profile); } /** handle generic bid via ortb2 arbitrary data @@ -823,14 +739,28 @@ class WeboramaRtdProvider { if (isBoolean(metadata.user)) { logMessage(`bidder '${bidder}' is not directly supported, trying set data via bidder ortb2 fpd`); const section = metadata.user ? 'user' : 'site'; - const base = `${bidder}.${section}.ext.data`; + const path = `${section}.ext.data`; - this.#assignProfileToObject(reqBidsConfigObj.ortb2Fragments?.bidder, base, profile); + this.#setBidderOrtb2(reqBidsConfigObj.ortb2Fragments?.bidder, bidder, path, profile) } else { logMessage(`SKIP unsupported bidder '${bidder}', data from '${metadata.source}' is not defined as user or site-centric`); } } - + /** + * set bidder ortb2 data + * @method + * @private + * @param {Object} bidderOrtb2Fragments + * @param {string} bidder + * @param {string} path + * @param {Profile} profile + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #setBidderOrtb2(bidderOrtb2Fragments, bidder, path, profile) { + const base = `${bidder}.${path}`; + this.#assignProfileToObject(bidderOrtb2Fragments, base, profile) + } /** * assign profile to object * @method diff --git a/modules/weboramaRtdProvider.md b/modules/weboramaRtdProvider.md index f86351fe214..0c6e3339787 100644 --- a/modules/weboramaRtdProvider.md +++ b/modules/weboramaRtdProvider.md @@ -575,12 +575,9 @@ pbjs.que.push(function () { ### Supported Bidders -We currently support the following bidder adapters: +We currently support the following bidder adapters with dedicated code: -* SmartADServer SSP -* PubMatic SSP * AppNexus SSP -* Rubicon SSP We also set the bidder (and global, if no specific bidders are set on `sendToBidders`) ortb2 `site.ext.data` and `user.ext.data` sections (as arbitrary data). The following bidders may support it, to be sure, check the `First Party Data Support` on the feature list for the particular bidder from [here](https://docs.prebid.org/dev-docs/bidders). @@ -605,8 +602,11 @@ We also set the bidder (and global, if no specific bidders are set on `sendToBid * Opt Out Advertising * Ozone Project * Proxistore +* PubMatic SSP * Rise +* Rubicon SSP * Smaato +* Smart ADServer SSP * Sonobi * TheMediaGrid * TripleLift diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index 31e9b35f178..b0136cd21ea 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -12,6 +12,8 @@ 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 IMG_TYPE_ICON = 1; +const IMG_TYPE_MAIN = 3; export const spec = { code: BIDDER_CODE, @@ -183,24 +185,33 @@ export const spec = { } if (isNative(bidRequest, adType)) { - // there may be publishers still rely on it + const { native } = matchedBid; + const { assets } = native; bidResponse.adUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`; bidResponse.mediaType = NATIVE; - const nativeImageAssetObj = find(matchedBid.native.assets, asset => isMainImage(asset)); + const nativeIconAssetObj = find(assets, isImageAssetOfType(IMG_TYPE_ICON)); + const nativeImageAssetObj = find(assets, isImageAssetOfType(IMG_TYPE_MAIN)); const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : { url: '', w: 0, h: 0 }; - const nativeTitleAsset = find(matchedBid.native.assets, asset => hasValidProperty(asset, 'title')); - const nativeBodyAsset = find(matchedBid.native.assets, asset => hasValidProperty(asset, 'data')); + const nativeTitleAsset = find(assets, asset => hasValidProperty(asset, 'title')); + const nativeBodyAsset = find(assets, asset => hasValidProperty(asset, 'data')); bidResponse.native = { title: nativeTitleAsset ? nativeTitleAsset.title.text : '', body: nativeBodyAsset ? nativeBodyAsset.data.value : '', + ...nativeIconAssetObj?.img && { + icon: { + url: nativeIconAssetObj.img.url, + width: nativeIconAssetObj.img.w, + height: nativeIconAssetObj.img.h, + }, + }, image: { url: nativeImageAsset.url, width: nativeImageAsset.w, height: nativeImageAsset.h, }, - clickUrl: matchedBid.native.link.url, - impressionTrackers: matchedBid.native.imptrackers, - assets: matchedBid.native.assets, + clickUrl: native.link.url, + impressionTrackers: native.imptrackers, + assets: assets, }; } @@ -517,14 +528,12 @@ function hasValidProperty(obj, propName) { } /** - * Checks if an asset object is a main image. - * A main image is defined as an image asset whose type value is 3. - * - * @param {Object} asset - The asset object to check. - * @returns {boolean} Returns true if the object has a property img.type with a value of 3, otherwise false. + * Returns a filtering function for image assets based on type. + * @param {number} type - The desired asset type to filter for i.e. IMG_TYPE_ICON = 1, IMG_TYPE_MAIN = 3 + * @returns {function} - A filtering function that accepts an asset and checks if its img.type matches the desired type. */ -function isMainImage(asset) { - return asset?.img?.type === 3 +function isImageAssetOfType(type) { + return asset => asset?.img?.type === type; } registerBidder(spec); diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index f0ad7522f1e..687afb6c692 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -11,11 +11,9 @@ const TIMEOUT_URL = 'https://ssp.disqus.com/timeout/prebid'; const USER_SYNC_URL_IFRAME = 'https://ssp.disqus.com/sync?type=iframe'; const USER_SYNC_URL_IMAGE = 'https://ssp.disqus.com/sync?type=image'; const DEFAULT_CUR = 'USD'; -const TTL = 200; +const TTL = 300; const NET_REV = true; -const VIDEO_REGEX = new RegExp(/VAST\s+version/); - const DATA_TYPES = { 'NUMBER': 'number', 'STRING': 'string', @@ -201,7 +199,10 @@ export const spec = { advertiserDomains: zetaBid.adomain }; } - provideMediaType(zetaBid, bid); + provideMediaType(zetaBid, bid, bidRequest.data); + if (bid.mediaType === VIDEO) { + bid.vastXml = bid.ad; + } bidResponses.push(bid); }) }) @@ -333,21 +334,11 @@ function provideEids(request, payload) { } } -function provideMediaType(zetaBid, bid) { - if (zetaBid.ext && zetaBid.ext.bidtype) { - if (zetaBid.ext.bidtype === VIDEO) { - bid.mediaType = VIDEO; - bid.vastXml = bid.ad; - } else { - bid.mediaType = BANNER; - } +function provideMediaType(zetaBid, bid, bidRequest) { + if (zetaBid.ext && zetaBid.ext.prebid && zetaBid.ext.prebid.type) { + bid.mediaType = zetaBid.ext.prebid.type === VIDEO ? VIDEO : BANNER; } else { - if (VIDEO_REGEX.test(bid.ad)) { - bid.mediaType = VIDEO; - bid.vastXml = bid.ad; - } else { - bid.mediaType = BANNER; - } + bid.mediaType = bidRequest.imp[0].video ? VIDEO : BANNER; } } diff --git a/package-lock.json b/package-lock.json index 2068ba8a7dd..dac41491b8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.53.0-pre", + "version": "7.54.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 5c55ec410d8..2dabb76c4ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.53.0-pre", + "version": "7.54.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { diff --git a/test/spec/modules/1plusXRtdProvider_spec.js b/test/spec/modules/1plusXRtdProvider_spec.js index 8657c37d7d8..66d0a74c194 100644 --- a/test/spec/modules/1plusXRtdProvider_spec.js +++ b/test/spec/modules/1plusXRtdProvider_spec.js @@ -1,16 +1,16 @@ +import assert from 'assert'; import { config } from 'src/config'; import { onePlusXSubmodule, - segtaxes, - extractConfig, buildOrtb2Updates, - updateBidderConfig, - setTargetingDataToConfig, + extractConfig, extractConsent, - getPapiUrl + extractFpid, + getPapiUrl, + segtaxes, + setTargetingDataToConfig, + updateBidderConfig, } from 'modules/1plusXRtdProvider'; -import assert from 'assert'; -import { extractFpid } from '../../../modules/1plusXRtdProvider'; describe('1plusXRtdProvider', () => { // Fake server config @@ -35,47 +35,37 @@ describe('1plusXRtdProvider', () => { // Bidder configs const bidderConfigInitial = { - ortb2: { - user: { keywords: '' }, - site: { ext: {} } - } + user: { keywords: '' }, + site: { ext: {} } } const bidderConfigInitialWith1plusXUserData = { - ortb2: { - user: { - data: [{ name: '1plusX.com', segment: [{ id: 'initial' }] }] - }, - site: { content: { data: [] } } - } + user: { + data: [{ name: '1plusX.com', segment: [{ id: 'initial' }] }] + }, + site: { content: { data: [] } } } const bidderConfigInitialWithUserData = { - ortb2: { - user: { - data: [{ name: 'hello.world', segment: [{ id: 'initial' }] }] - }, - site: { content: { data: [] } } - } + user: { + data: [{ name: 'hello.world', segment: [{ id: 'initial' }] }] + }, + site: { content: { data: [] } } } const bidderConfigInitialWith1plusXSiteContent = { - ortb2: { - user: { data: [] }, - site: { - content: { - data: [{ - name: '1plusX.com', segment: [{ id: 'initial' }], ext: { segtax: 525 } - }] - } - }, + user: { data: [] }, + site: { + content: { + data: [{ + name: '1plusX.com', segment: [{ id: 'initial' }], ext: { segtax: 525 } + }] + } } } const bidderConfigInitialWithSiteContent = { - ortb2: { - user: { data: [] }, - site: { - content: { - data: [{ name: 'hello.world', segment: [{ id: 'initial' }] }] - } - }, + user: { data: [] }, + site: { + content: { + data: [{ name: 'hello.world', segment: [{ id: 'initial' }] }] + } } } // Util functions @@ -178,7 +168,7 @@ describe('1plusXRtdProvider', () => { }) describe('buildOrtb2Updates', () => { - it('fills site.content.data & user.data in the ortb2 config', () => { + it('fills site.content.data, user.data & site.keywords in the ortb2 config', () => { const rtdData = { segments: fakeResponse.s, topics: fakeResponse.t }; const ortb2Updates = buildOrtb2Updates(rtdData, randomBidder()); @@ -191,18 +181,8 @@ describe('1plusXRtdProvider', () => { userData: { name: '1plusX.com', segment: rtdData.segments.map((segmentId) => ({ id: segmentId })) - } - } - expect([ortb2Updates]).to.deep.include.members([expectedOutput]); - }); - it('fills site.keywords in the ortb2 config (appnexus specific)', () => { - const rtdData = { segments: fakeResponse.s, topics: fakeResponse.t }; - const ortb2Updates = buildOrtb2Updates(rtdData, 'appnexus'); - - const expectedOutput = { - site: { - keywords: rtdData.topics.join(','), - } + }, + siteKeywords: rtdData.topics.map(topic => `1plusX=${topic}`).join(','), } expect([ortb2Updates]).to.deep.include.members([expectedOutput]); }); @@ -220,7 +200,8 @@ describe('1plusXRtdProvider', () => { userData: { name: '1plusX.com', segment: [] - } + }, + siteKeywords: rtdData.topics.map(topic => `1plusX=${topic}`).join(','), } expect(ortb2Updates).to.deep.include(expectedOutput); }) @@ -238,20 +219,10 @@ describe('1plusXRtdProvider', () => { userData: { name: '1plusX.com', segment: rtdData.segments.map((segmentId) => ({ id: segmentId })) - } - } - expect(ortb2Updates).to.deep.include(expectedOutput); - }) - it('defaults to empty string if no topic is given (appnexus specific)', () => { - const rtdData = { segments: fakeResponse.s }; - const ortb2Updates = buildOrtb2Updates(rtdData, 'appnexus'); - - const expectedOutput = { - site: { - keywords: '', - } + }, + siteKeywords: '', } - expect(ortb2Updates).to.deep.include(expectedOutput); + expect(ortb2Updates, `${JSON.stringify(ortb2Updates, null, 2)}`).to.deep.include(expectedOutput); }) }) @@ -271,6 +242,7 @@ describe('1plusXRtdProvider', () => { expect(expectedOutput).to.deep.include(output) expect(output).to.deep.include(expectedOutput) }) + it('extracts null if consent object is empty', () => { const consent1 = {} expect(extractConsent(consent1)).to.equal(null) @@ -345,15 +317,6 @@ describe('1plusXRtdProvider', () => { }) describe('updateBidderConfig', () => { - const ortb2UpdatesAppNexus = { - site: { - keywords: fakeResponse.t.join(','), - }, - userData: { - name: '1plusX.com', - segment: fakeResponse.s.map((segmentId) => ({ id: segmentId })) - } - } const ortb2Updates = { siteContentData: { name: '1plusX.com', @@ -363,114 +326,98 @@ describe('1plusXRtdProvider', () => { userData: { name: '1plusX.com', segment: fakeResponse.s.map((segmentId) => ({ id: segmentId })) - } + }, + siteKeywords: fakeResponse.t.map(topic => `1plusX=${topic}`).join(','), } it('merges fetched data in bidderConfig for configured bidders', () => { - const bidder = randomBidder(); - // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitial - }); - // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2Updates, config.getBidderConfig()); - // Check that the targeting data has been set in the config - expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.site.content.data).to.deep.include(ortb2Updates.siteContentData); - expect(newBidderConfig.ortb2.user.data).to.deep.include(ortb2Updates.userData); - // Check that existing config didn't get erased - expect(newBidderConfig.ortb2.site).to.deep.include(bidderConfigInitial.ortb2.site); - expect(newBidderConfig.ortb2.user).to.deep.include(bidderConfigInitial.ortb2.user); - }) - - it('merges fetched data in bidderConfig for configured bidders (appnexus specific)', () => { - const bidder = 'appnexus'; // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitial - }); + const bidder = randomBidder(); + const ortb2Fragments = { [bidder]: { ...bidderConfigInitial } } // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2UpdatesAppNexus, config.getBidderConfig()); - + updateBidderConfig(bidder, ortb2Updates, ortb2Fragments); + const newBidderConfig = ortb2Fragments[bidder]; // Check that the targeting data has been set in the config - expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.site).to.deep.include(ortb2UpdatesAppNexus.site); + expect(newBidderConfig).not.to.be.null.and.not.to.be.undefined; + expect(newBidderConfig.user).not.to.be.null.and.not.to.be.undefined; + expect(newBidderConfig.site).not.to.be.null.and.not.to.be.undefined; + expect(newBidderConfig.user.data).to.deep.include(ortb2Updates.userData); + expect(newBidderConfig.site.keywords).to.deep.include(ortb2Updates.siteKeywords); + expect(newBidderConfig.site.content.data).to.deep.include(ortb2Updates.siteContentData); // Check that existing config didn't get erased - expect(newBidderConfig.ortb2.site).to.deep.include(bidderConfigInitial.ortb2.site); - expect(newBidderConfig.ortb2.user).to.deep.include(bidderConfigInitial.ortb2.user); + expect(newBidderConfig.site).to.deep.include(bidderConfigInitial.site); + expect(newBidderConfig.user).to.deep.include(bidderConfigInitial.user); }) it('overwrites an existing 1plus.com entry in ortb2.user.data', () => { - const bidder = randomBidder(); // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitialWith1plusXUserData - }); + const bidder = randomBidder(); + const ortb2Fragments = { [bidder]: { ...bidderConfigInitialWith1plusXUserData } } // Save previous user.data entry - const previousUserData = bidderConfigInitialWith1plusXUserData.ortb2.user.data[0]; + const previousUserData = bidderConfigInitialWith1plusXUserData.user.data[0]; // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2Updates, config.getBidderConfig()); + updateBidderConfig(bidder, ortb2Updates, ortb2Fragments); + const newBidderConfig = ortb2Fragments[bidder]; // Check that the targeting data has been set in the config expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.user.data).to.deep.include(ortb2Updates.userData); - expect(newBidderConfig.ortb2.user.data).not.to.include(previousUserData); + expect(newBidderConfig.site).not.to.be.null; + expect(newBidderConfig.user).not.to.be.null; + expect(newBidderConfig.user.data).to.deep.include(ortb2Updates.userData); + expect(newBidderConfig.user.data).not.to.include(previousUserData); }) it("doesn't overwrite entries in ortb2.user.data that aren't 1plusx.com", () => { - const bidder = randomBidder(); // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitialWithUserData - }); + const bidder = randomBidder(); + const ortb2Fragments = { [bidder]: { ...bidderConfigInitialWithUserData } } // Save previous user.data entry - const previousUserData = bidderConfigInitialWithUserData.ortb2.user.data[0]; + const previousUserData = bidderConfigInitialWithUserData.user.data[0]; // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2Updates, config.getBidderConfig()); + updateBidderConfig(bidder, ortb2Updates, ortb2Fragments); + const newBidderConfig = ortb2Fragments[bidder]; // Check that the targeting data has been set in the config expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.user.data).to.deep.include(ortb2Updates.userData); - expect(newBidderConfig.ortb2.user.data).to.deep.include(previousUserData); + expect(newBidderConfig.site).not.to.be.null; + expect(newBidderConfig.user).not.to.be.null; + expect(newBidderConfig.user.data).to.deep.include(ortb2Updates.userData); + expect(newBidderConfig.user.data).to.deep.include(previousUserData); }) it('overwrites an existing 1plus.com entry in ortb2.site.content.data', () => { - const bidder = randomBidder(); // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitialWith1plusXSiteContent - }); + const bidder = randomBidder(); + const ortb2Fragments = { [bidder]: { ...bidderConfigInitialWith1plusXSiteContent } } // Save previous user.data entry - const previousSiteContent = bidderConfigInitialWith1plusXSiteContent.ortb2.site.content.data[0]; + const previousSiteContent = bidderConfigInitialWith1plusXSiteContent.site.content.data[0]; // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2Updates, config.getBidderConfig()); + updateBidderConfig(bidder, ortb2Updates, ortb2Fragments); + const newBidderConfig = ortb2Fragments[bidder]; // Check that the targeting data has been set in the config expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.site.content.data).to.deep.include(ortb2Updates.siteContentData); - expect(newBidderConfig.ortb2.site.content.data).not.to.include(previousSiteContent); + expect(newBidderConfig.site).not.to.be.null; + expect(newBidderConfig.user).not.to.be.null; + expect(newBidderConfig.site.content.data).to.deep.include(ortb2Updates.siteContentData); + expect(newBidderConfig.site.content.data).not.to.include(previousSiteContent); }) it("doesn't overwrite entries in ortb2.site.content.data that aren't 1plusx.com", () => { - const bidder = randomBidder(); // Set initial config - config.setBidderConfig({ - bidders: [bidder], - config: bidderConfigInitialWithSiteContent - }); + const bidder = randomBidder(); + const ortb2Fragments = { [bidder]: { ...bidderConfigInitialWithSiteContent } } // Save previous user.data entry - const previousSiteContent = bidderConfigInitialWithSiteContent.ortb2.site.content.data[0]; + const previousSiteContent = bidderConfigInitialWithSiteContent.site.content.data[0]; // Call submodule's setBidderConfig - const newBidderConfig = updateBidderConfig(bidder, ortb2Updates, config.getBidderConfig()); + updateBidderConfig(bidder, ortb2Updates, ortb2Fragments); + const newBidderConfig = ortb2Fragments[bidder]; // Check that the targeting data has been set in the config expect(newBidderConfig).not.to.be.null; - expect(newBidderConfig.ortb2.site.content.data).to.deep.include(ortb2Updates.siteContentData); - expect(newBidderConfig.ortb2.site.content.data).to.deep.include(previousSiteContent); + expect(newBidderConfig.site).not.to.be.null; + expect(newBidderConfig.user).not.to.be.null; + expect(newBidderConfig.site.content.data).to.deep.include(ortb2Updates.siteContentData); + expect(newBidderConfig.site.content.data).to.deep.include(previousSiteContent); }) }) describe('setTargetingDataToConfig', () => { - const expectedKeywords = fakeResponse.t.join(','); + const expectedKeywords = fakeResponse.t.map(topic => `1plusX=${topic}`).join(','); const expectedSiteContentObj = { data: [{ name: '1plusX.com', @@ -486,10 +433,11 @@ describe('1plusXRtdProvider', () => { } const expectedOrtb2 = { appnexus: { - site: { keywords: expectedKeywords } + site: { content: expectedSiteContentObj, keywords: expectedKeywords }, + user: expectedUserObj }, rubicon: { - site: { content: expectedSiteContentObj }, + site: { content: expectedSiteContentObj, keywords: expectedKeywords }, user: expectedUserObj } } @@ -501,22 +449,23 @@ describe('1plusXRtdProvider', () => { bidders, config: bidderConfigInitial }) + const biddersOrtb2 = config.getBidderConfig(); // call setTargetingDataToConfig - setTargetingDataToConfig(fakeResponse, { bidders }); + setTargetingDataToConfig(fakeResponse, { bidders, biddersOrtb2 }); // Check that the targeting data has been set in both configs for (const bidder of bidders) { const newConfig = config.getBidderConfig()[bidder]; // Check that we got what we expect const expectedConfErr = (prop) => `New config for ${bidder} doesn't comply with expected at ${prop}`; - expect(newConfig.ortb2.site, expectedConfErr('site')).to.deep.include(expectedOrtb2[bidder].site); + expect(newConfig.site, expectedConfErr('site')).to.deep.include(expectedOrtb2[bidder].site); if (expectedOrtb2[bidder].user) { - expect(newConfig.ortb2.user, expectedConfErr('user')).to.deep.include(expectedOrtb2[bidder].user); + expect(newConfig.user, expectedConfErr('user')).to.deep.include(expectedOrtb2[bidder].user); } // Check that existing config didn't get erased const existingConfErr = (prop) => `Existing config for ${bidder} got unlawfully overwritten at ${prop}`; - expect(newConfig.ortb2.site, existingConfErr('site')).to.deep.include(bidderConfigInitial.ortb2.site); - expect(newConfig.ortb2.user, existingConfErr('user')).to.deep.include(bidderConfigInitial.ortb2.user); + expect(newConfig.site, existingConfErr('site')).to.deep.include(bidderConfigInitial.site); + expect(newConfig.user, existingConfErr('user')).to.deep.include(bidderConfigInitial.user); } }) }) diff --git a/test/spec/modules/adhashBidAdapter_spec.js b/test/spec/modules/adhashBidAdapter_spec.js index 2d3458fff79..cc643d6d2ab 100644 --- a/test/spec/modules/adhashBidAdapter_spec.js +++ b/test/spec/modules/adhashBidAdapter_spec.js @@ -88,7 +88,7 @@ describe('adhashBidAdapter', function () { ); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.6&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -104,7 +104,7 @@ describe('adhashBidAdapter', function () { const result = spec.buildRequests([ bidRequest ], { gdprConsent: { gdprApplies: true, consentString: 'example' } }); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.6&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -152,6 +152,8 @@ describe('adhashBidAdapter', function () { ['дума', 'full', 1], ['старт', 'starts', 1], ['край', 'ends', 1], + ['onq jbeq', 'partial', 1], + ['dhrra qvrf', 'combo', 2], ], maxScore: 2 } @@ -196,6 +198,13 @@ describe('adhashBidAdapter', function () { expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); + it('should return empty array when there are bad words (partial, compound phrase)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text partialbad wordb bad wordb example bad wordbtext' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + it('should return empty array when there are bad words (starts)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { return 'example text startsWith starts text startsAgain' + ' word'.repeat(994); @@ -224,6 +233,13 @@ describe('adhashBidAdapter', function () { expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); + it('should return empty array when there are bad words (combo)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'queen of england dies, the queen dies' + ' word'.repeat(993); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + it('should return empty array when there are bad words (regexp)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { return 'example text xxxayyy zzxxxAyyyzz text xxxbyyy' + ' word'.repeat(994); diff --git a/test/spec/modules/beopBidAdapter_spec.js b/test/spec/modules/beopBidAdapter_spec.js index 9d3c00b368b..22c48c2d182 100644 --- a/test/spec/modules/beopBidAdapter_spec.js +++ b/test/spec/modules/beopBidAdapter_spec.js @@ -130,6 +130,30 @@ describe('BeOp Bid Adapter tests', () => { expect(payload.url).to.exist; // check that the protocol is added correctly expect(payload.url).to.equal('http://test.te'); + expect(payload.psegs).to.not.exist; + }); + + it('should call the endpoint with psegs data if any', function () { + let bidderRequest = + { + 'ortb2': { + 'user': { + 'ext': { + 'data': { + 'permutive': [1234, 5678, 910] + } + } + } + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.psegs).to.exist; + expect(payload.psegs).to.include(1234); + expect(payload.psegs).to.include(5678); + expect(payload.psegs).to.include(910); + expect(payload.psegs).to.not.include(1); }); it('should not prepend the protocol in page url if already present', function () { diff --git a/test/spec/modules/conceptxBidAdapter_spec.js b/test/spec/modules/conceptxBidAdapter_spec.js new file mode 100644 index 00000000000..349ee765b71 --- /dev/null +++ b/test/spec/modules/conceptxBidAdapter_spec.js @@ -0,0 +1,136 @@ +// import or require modules necessary for the test, e.g.: +import { expect } from 'chai'; // may prefer 'assert' in place of 'expect' +import { spec } from 'modules/conceptxBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +// import { config } from 'src/config.js'; + +describe('conceptxBidAdapter', function () { + const URL = 'https://conceptx.cncpt-central.com/openrtb'; + + // before(() => { + + // }); + + // after(() => { + // // $$PREBID_GLOBAL$$.bidderSettings = {}; + // }); + + // afterEach(function () { + // config.resetConfig(); + // }); + + const ENDPOINT_URL = `${URL}`; + const ENDPOINT_URL_CONSENT = `${URL}?gdpr_applies=true&consentString=ihaveconsented`; + const adapter = newBidder(spec); + + const bidderRequests = [ + { + bidId: '123', + bidder: 'conceptx', + params: { + site: 'example', + adunit: 'some-id-3' + }, + mediaTypes: { + banner: { + sizes: [[930, 180]], + } + }, + } + ] + + const singleBidRequest = { + bid: [ + { + bidId: '123', + } + ] + } + + const serverResponse = { + body: { + 'bidResponses': [ + { + 'ads': [ + { + 'referrer': 'http://localhost/prebidpage_concept_bidder.html', + 'ttl': 360, + 'html': '

DUMMY

', + 'requestId': '214dfadd1f8826', + 'cpm': 46, + 'currency': 'DKK', + 'width': 930, + 'height': 180, + 'creativeId': 'FAKE-ID', + 'meta': { + 'mediaType': 'banner' + }, + 'netRevenue': true, + 'destinationUrls': { + 'destination': 'https://concept.dk' + } + } + ], + 'matchedAdCount': 1, + 'targetId': '214dfadd1f8826' + } + ] + } + } + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bidderRequests[0])).to.equal(true); + }); + }); + + describe('buildRequests', function () { + it('Test requests', function () { + const request = spec.buildRequests(bidderRequests, {}); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('data'); + const bid = JSON.parse(request[0].data).adUnits[0] + expect(bid.site).to.equal('example'); + expect(bid.adunit).to.equal('some-id-3'); + expect(JSON.stringify(bid.dimensions)).to.equal(JSON.stringify([ + [930, 180]])); + }); + }); + + describe('user privacy', function () { + it('should NOT send GDPR Consent data if gdprApplies equals undefined', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: undefined, consentString: 'iDoNotConsent' } }); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('url') + expect(request[0].url).to.equal(ENDPOINT_URL); + }); + it('should send GDPR Consent data if gdprApplies', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: true, consentString: 'ihaveconsented' } }); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('url') + expect(request[0].url).to.equal(ENDPOINT_URL_CONSENT); + }); + }); + + describe('interpretResponse', function () { + it('should return valid response when passed valid server response', function () { + const interpretedResponse = spec.interpretResponse(serverResponse, singleBidRequest); + const ad = serverResponse.body.bidResponses[0].ads[0] + expect(interpretedResponse).to.have.lengthOf(1); + expect(interpretedResponse[0].cpm).to.equal(ad.cpm); + expect(interpretedResponse[0].width).to.equal(Number(ad.width)); + expect(interpretedResponse[0].height).to.equal(Number(ad.height)); + expect(interpretedResponse[0].creativeId).to.equal(ad.creativeId); + expect(interpretedResponse[0].currency).to.equal(ad.currency); + expect(interpretedResponse[0].netRevenue).to.equal(true); + expect(interpretedResponse[0].ad).to.equal(ad.html); + expect(interpretedResponse[0].ttl).to.equal(360); + }); + }); +}); diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index ff4e895ff2f..b2f3d64a156 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -2527,7 +2527,7 @@ describe('The Criteo bidding adapter', function () { const adapters = { Prebid: function () { } }; const adaptersMock = sinon.mock(adapters); - adaptersMock.expects('Prebid').withExactArgs(PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$').once().returns(prebidAdapter); + adaptersMock.expects('Prebid').withExactArgs(PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$', sinon.match.any).once().returns(prebidAdapter); global.Criteo = { PubTag: { diff --git a/test/spec/modules/freepassIdSystem_spec.js b/test/spec/modules/freepassIdSystem_spec.js new file mode 100644 index 00000000000..f7407f5eb94 --- /dev/null +++ b/test/spec/modules/freepassIdSystem_spec.js @@ -0,0 +1,186 @@ +import {freepassIdSubmodule} from 'modules/freepassIdSystem'; +import sinon from 'sinon'; +import * as utils from '../../../src/utils'; + +let expect = require('chai').expect; + +describe('FreePass ID System', function () { + const UUID = '15fde1dc-1861-4894-afdf-b757272f3568'; + + before(function () { + sinon.stub(utils, 'generateUUID').returns(UUID); + sinon.stub(utils, 'logMessage'); + }); + + after(function () { + utils.generateUUID.restore(); + utils.logMessage.restore(); + }); + + describe('freepassIdSubmodule', function () { + it('should expose submodule name', function () { + expect(freepassIdSubmodule.name).to.equal('freepassId'); + }); + }); + + describe('getId', function () { + const config = { + storage: { + name: '_freepassId', + type: 'cookie', + expires: 30 + }, + params: { + freepassData: { + commonId: 'commonId', + userIp: '127.0.0.1' + } + } + }; + + it('should return an IdObject with a UUID', function () { + const objectId = freepassIdSubmodule.getId(config, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.userId).to.equal(UUID); + }); + + it('should include userIp in IdObject', function () { + const objectId = freepassIdSubmodule.getId(config, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.userIp).to.equal('127.0.0.1'); + }); + it('should skip userIp in IdObject if not available', function () { + const localConfig = Object.assign({}, config); + delete localConfig.params.freepassData.userIp; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.userIp).to.be.undefined; + }); + it('should skip userIp in IdObject if freepassData is not available', function () { + const localConfig = JSON.parse(JSON.stringify(config)); + delete localConfig.params.freepassData; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.userIp).to.be.undefined; + }); + it('should skip userIp in IdObject if params is not available', function () { + const localConfig = JSON.parse(JSON.stringify(config)); + delete localConfig.params; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.userIp).to.be.undefined; + }); + it('should include commonId in IdObject', function () { + const objectId = freepassIdSubmodule.getId(config, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.commonId).to.equal('commonId'); + }); + it('should skip commonId in IdObject if not available', function () { + const localConfig = Object.assign({}, config); + delete localConfig.params.freepassData.commonId; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.commonId).to.be.undefined; + }); + it('should skip commonId in IdObject if freepassData is not available', function () { + const localConfig = JSON.parse(JSON.stringify(config)); + delete localConfig.params.freepassData; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.commonId).to.be.undefined; + }); + it('should skip commonId in IdObject if params is not available', function () { + const localConfig = JSON.parse(JSON.stringify(config)); + delete localConfig.params; + const objectId = freepassIdSubmodule.getId(localConfig, undefined); + expect(objectId).to.be.an('object'); + expect(objectId.id).to.be.an('object'); + expect(objectId.id.commonId).to.be.undefined; + }); + }); + + describe('decode', function () { + it('should have module name as property', function () { + const decodedId = freepassIdSubmodule.decode({}, {}); + expect(decodedId).to.be.an('object'); + expect(decodedId).to.have.property('freepassId'); + }); + it('should have IObject as property value', function () { + const idObject = { + commonId: 'commonId', + userIp: '127.0.0.1', + userId: UUID + }; + const decodedId = freepassIdSubmodule.decode(idObject, {}); + expect(decodedId).to.be.an('object'); + expect(decodedId.freepassId).to.be.an('object'); + expect(decodedId.freepassId).to.equal(idObject); + }); + }); + + describe('extendId', function () { + const config = { + storage: { + name: '_freepassId', + type: 'cookie', + expires: 30 + }, + params: { + freepassData: { + commonId: 'commonId', + userIp: '127.0.0.1' + } + } + }; + + it('should return cachedIdObject if there are no changes', function () { + const idObject = freepassIdSubmodule.getId(config, undefined); + const cachedIdObject = Object.assign({}, idObject.id); + const extendedIdObject = freepassIdSubmodule.extendId(config, undefined, cachedIdObject); + expect(extendedIdObject).to.be.an('object'); + expect(extendedIdObject.id).to.be.an('object'); + expect(extendedIdObject.id).to.equal(cachedIdObject); + }); + + it('should return cachedIdObject if there are no new data', function () { + const idObject = freepassIdSubmodule.getId(config, undefined); + const cachedIdObject = Object.assign({}, idObject.id); + const localConfig = JSON.parse(JSON.stringify(config)); + delete localConfig.params.freepassData; + const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject); + expect(extendedIdObject).to.be.an('object'); + expect(extendedIdObject.id).to.be.an('object'); + expect(extendedIdObject.id).to.equal(cachedIdObject); + }); + + it('should return new commonId if there are changes', function () { + const idObject = freepassIdSubmodule.getId(config, undefined); + const cachedIdObject = Object.assign({}, idObject.id); + const localConfig = JSON.parse(JSON.stringify(config)); + localConfig.params.freepassData.commonId = 'newCommonId'; + const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject); + expect(extendedIdObject).to.be.an('object'); + expect(extendedIdObject.id).to.be.an('object'); + expect(extendedIdObject.id.commonId).to.equal('newCommonId'); + }); + + it('should return new userIp if there are changes', function () { + const idObject = freepassIdSubmodule.getId(config, undefined); + const cachedIdObject = Object.assign({}, idObject.id); + const localConfig = JSON.parse(JSON.stringify(config)); + localConfig.params.freepassData.userIp = '192.168.1.1'; + const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject); + expect(extendedIdObject).to.be.an('object'); + expect(extendedIdObject.id).to.be.an('object'); + expect(extendedIdObject.id.userIp).to.equal('192.168.1.1'); + }); + }); +}); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index e566088d991..783d273e425 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -2575,6 +2575,36 @@ describe('IndexexchangeAdapter', function () { expect(impression.video.placement).to.equal(2); }); + it('should use plcmt value when set in video.params', function () { + const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); + bid.params.video.plcmt = 2; + const request = spec.buildRequests([bid], {})[0]; + const impression = extractPayload(request).imp[0]; + + expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); + expect(impression.video.plcmt).to.equal(2); + }); + + it('invalid plcmt value when set in video.params', function () { + const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); + bid.params.video.plcmt = 5; + const request = spec.buildRequests([bid], {})[0]; + const impression = extractPayload(request).imp[0]; + + expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); + expect(impression.video.plcmt).to.be.undefined; + }); + + it('invalid plcmt value string when set in video.params', function () { + const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); + bid.params.video.plcmt = '4'; + const request = spec.buildRequests([bid], {})[0]; + const impression = extractPayload(request).imp[0]; + + expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); + expect(impression.video.plcmt).to.be.undefined; + }); + it('should set imp.ext.sid for video imps if params.id exists', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.params.id = 50; diff --git a/test/spec/modules/mediasquareBidAdapter_spec.js b/test/spec/modules/mediasquareBidAdapter_spec.js index bcf3c6852e7..4e131024d84 100644 --- a/test/spec/modules/mediasquareBidAdapter_spec.js +++ b/test/spec/modules/mediasquareBidAdapter_spec.js @@ -98,6 +98,7 @@ describe('MediaSquare bid adapter tests', function () { 'code': 'test/publishername_atf_desktop_rg_pave', 'bid_id': 'aaaa1234', 'adomain': ['test.com'], + 'context': 'instream', }], }}; @@ -161,7 +162,10 @@ describe('MediaSquare bid adapter tests', function () { expect(bid.ttl).to.equal(300); expect(bid.requestId).to.equal('aaaa1234'); expect(bid.mediasquare).to.exist; + expect(bid.mediasquare.bidder).to.exist; expect(bid.mediasquare.bidder).to.equal('msqClassic'); + expect(bid.mediasquare.context).to.exist; + expect(bid.mediasquare.context).to.equal('instream'); expect(bid.mediasquare.code).to.equal([DEFAULT_PARAMS[0].params.owner, DEFAULT_PARAMS[0].params.code].join('/')); expect(bid.meta).to.exist; expect(bid.meta.advertiserDomains).to.exist; diff --git a/test/spec/modules/sirdataRtdProvider_spec.js b/test/spec/modules/sirdataRtdProvider_spec.js index eccc4777906..fbb5967bc20 100644 --- a/test/spec/modules/sirdataRtdProvider_spec.js +++ b/test/spec/modules/sirdataRtdProvider_spec.js @@ -1,26 +1,31 @@ -import {addSegmentData, getSegmentsAndCategories, sirdataSubmodule} from 'modules/sirdataRtdProvider.js'; +import {addSegmentData, getSegmentsAndCategories, sirdataSubmodule, setOrtb2} from 'modules/sirdataRtdProvider.js'; import {server} from 'test/mocks/xhr.js'; const responseHeader = {'Content-Type': 'application/json'}; describe('sirdataRtdProvider', function () { describe('sirdataSubmodule', function () { + it('exists', function () { + expect(sirdataSubmodule.init).to.be.a('function'); + }); it('successfully instantiates', function () { expect(sirdataSubmodule.init()).to.equal(true); }); + it('has the correct module name', function () { + expect(sirdataSubmodule.name).to.equal('SirdataRTDModule'); + }); }); describe('Add Segment Data', function () { it('adds segment data', function () { - const config = { + const firstConfig = { params: { - setGptKeyValues: false, + partnerId: 1, + key: 1, + setGptKeyValues: true, + gptCurationId: 27449, contextualMinRelevancyScore: 50, - bidders: [{ - bidder: 'appnexus' - }, { - bidder: 'other' - }] + bidders: [] } }; @@ -37,21 +42,47 @@ describe('sirdataRtdProvider', function () { } ]; - let data = { + let firstReqBidsConfigObj = { + adUnits: adUnits, + ortb2Fragments: { + global: {} + } + }; + + let firstData = { segments: [111111, 222222], - contextual_categories: {'333333': 100} + contextual_categories: {'333333': 100}, + 'segtaxid': null, + 'cattaxid': null, + 'shared_taxonomy': { + '27449': { + 'segments': [444444, 555555], + 'segtaxid': null, + 'cattaxid': null, + 'contextual_categories': {'666666': 100} + } + }, + 'global_taxonomy': { + '9998': { + 'segments': [123, 234], + 'segtaxid': 4, + 'cattaxid': 7, + 'contextual_categories': {'345': 100, '456': 100} + } + } }; - addSegmentData({adUnits}, data, config, () => { + addSegmentData(firstReqBidsConfigObj, firstData, firstConfig, () => { }); - expect(adUnits[0].bids[0].params.keywords).to.have.deep.property('sd_rtd', ['111111', '222222', '333333']); + + expect(firstReqBidsConfigObj.ortb2Fragments.global.user.data[0].ext.segtax).to.equal(4); }); }); describe('Get Segments And Categories', function () { it('gets data from async request and adds segment data', function () { const overrideAppnexus = function (adUnit, list, data, bid) { - deepSetValue(bid, 'params.keywords.custom', list); + deepSetValue(bid, 'params.keywords.custom', list.segments.concat(list.categories)); } const config = { @@ -60,16 +91,21 @@ describe('sirdataRtdProvider', function () { contextualMinRelevancyScore: 50, bidders: [{ bidder: 'appnexus', - customFunction: overrideAppnexus + customFunction: overrideAppnexus, + curationId: 27446 }, { - bidder: 'smartadserver' + bidder: 'smartadserver', + curationId: 27440 }, { bidder: 'ix', sizeLimit: 1200, + curationId: 27248 }, { bidder: 'rubicon', + curationId: 27452 }, { bidder: 'proxistore', + curationId: 27484 }] } }; @@ -146,6 +182,12 @@ describe('sirdataRtdProvider', function () { 'segtaxid': 552, 'cattaxid': 553, 'contextual_categories': {'666666': 100} + }, + '27446': { + 'segments': [777777, 888888], + 'segtaxid': 552, + 'cattaxid': 553, + 'contextual_categories': {'999999': 100} } }, 'global_taxonomy': { @@ -164,8 +206,6 @@ describe('sirdataRtdProvider', function () { let request = server.requests[0]; request.respond(200, responseHeader, JSON.stringify(data)); - expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.have.deep.property('target', 'sd_rtd=111111;sd_rtd=222222;sd_rtd=333333;sd_rtd=444444;sd_rtd=555555;sd_rtd=666666'); - expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].name).to.equal( 'sirdata.com' ); @@ -185,4 +225,57 @@ describe('sirdataRtdProvider', function () { expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].ext.segtax).to.equal(4); }); }); + + describe('Set ortb2 for bidder', function () { + it('set ortb2 for a givent bidder', function () { + const config = { + params: { + setGptKeyValues: false, + contextualMinRelevancyScore: 50, + bidders: [{ + bidder: 'appnexus', + }] + } + }; + + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] + }], + ortb2Fragments: { + global: {} + } + }; + + let data = { + 'segments': [111111, 222222], + 'segtaxid': null, + 'cattaxid': null, + 'contextual_categories': {'333333': 100}, + 'shared_taxonomy': { + '27440': { + 'segments': [444444, 555555], + 'segtaxid': null, + 'cattaxid': null, + 'contextual_categories': {'666666': 100} + } + }, + 'global_taxonomy': {} + }; + + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + + let test = setOrtb2(reqBidsConfigObj.ortb2Fragments, 'appnexus', 'user', []); + expect(test).to.be.false; + + test = setOrtb2(reqBidsConfigObj.ortb2Fragments, 'appnexus', 'user', ['1']); + expect(test).to.be.true; + }); + }); }); diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 831d3ae0315..c84013d1963 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -170,6 +170,19 @@ describe('sovrnBidAdapter', function() { expect(payload.site.domain).to.equal('example.com') }) + it('sets correct timeout', function() { + const bidderRequest = { + ...baseBidderRequest, + bidderCode: 'sovrn', + auctionId: '1d1a030790a475', + bidderRequestId: '22edbae2733bf6', + timeout: 3000, + bids: [baseBidRequest] + } + const payload = JSON.parse(spec.buildRequests([baseBidRequest], bidderRequest).data) + expect(payload.tmax).to.equal(3000) + }) + it('includes the ad unit code in the request', function() { const impression = payload.imp[0] expect(impression.adunitcode).to.equal('adunit-code') diff --git a/test/spec/modules/stroeerCoreBidAdapter_spec.js b/test/spec/modules/stroeerCoreBidAdapter_spec.js index c2806317ee6..55d79804a38 100644 --- a/test/spec/modules/stroeerCoreBidAdapter_spec.js +++ b/test/spec/modules/stroeerCoreBidAdapter_spec.js @@ -527,14 +527,16 @@ describe('stroeerCore bid adapter', function () { 'bid': 'bid8', 'viz': true, 'ban': { - 'siz': [[300, 600], [160, 60]] - } + 'siz': [[300, 600], [160, 60]], + 'fp': undefined + }, }, { 'sid': 'ABC=', 'bid': 'bid12', 'ban': { - 'siz': [[100, 200], [300, 500]] + 'siz': [[100, 200], [300, 500]], + 'fp': undefined }, 'viz': undefined } @@ -548,7 +550,8 @@ describe('stroeerCore bid adapter', function () { 'vid': { 'ctx': 'instream', 'siz': [640, 480], - 'mim': ['video/mp4', 'video/quicktime'] + 'mim': ['video/mp4', 'video/quicktime'], + 'fp': undefined } } ]; @@ -589,7 +592,8 @@ describe('stroeerCore bid adapter', function () { 'bid': 'bid3', 'viz': true, 'ban': { - 'siz': [[100, 200], [300, 500]] + 'siz': [[100, 200], [300, 500]], + 'fp': undefined } } ]; @@ -602,7 +606,8 @@ describe('stroeerCore bid adapter', function () { 'vid': { 'ctx': 'instream', 'siz': [640, 480], - 'mim': ['video/mp4', 'video/quicktime'] + 'mim': ['video/mp4', 'video/quicktime'], + 'fp': undefined } } ]; @@ -696,6 +701,146 @@ describe('stroeerCore bid adapter', function () { const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq); assert.deepEqual(serverRequestInfo.data.schain, schain); }); + + it('should add floor info to banner bid request if floor is available', () => { + const bidReq = buildBidderRequest(); + + const getFloorStub1 = sinon.stub(); + const getFloorStub2 = sinon.stub(); + + getFloorStub1 + .returns({}) + .withArgs({currency: 'EUR', mediaType: BANNER, size: '*'}) + .returns({currency: 'TRY', floor: 0.7}) + .withArgs({currency: 'EUR', mediaType: 'banner', size: [300, 600]}) + .returns({currency: 'TRY', floor: 1.3}) + .withArgs({currency: 'EUR', mediaType: 'banner', size: [160, 60]}) + .returns({currency: 'TRY', floor: 2.5}) + + getFloorStub2 + .returns({}) + .withArgs({currency: 'EUR', mediaType: 'banner', size: '*'}) + .returns({currency: 'USD', floor: 1.2}) + .withArgs({currency: 'EUR', mediaType: 'banner', size: [728, 90]}) + .returns({currency: 'USD', floor: 1.85}) + + bidReq.bids[0].getFloor = getFloorStub1; + bidReq.bids[1].getFloor = getFloorStub2; + + const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq); + + const serverRequestBids = serverRequestInfo.data.bids; + const firstBid = serverRequestBids[0]; + const secondBid = serverRequestBids[1]; + + assert.nestedPropertyVal(firstBid, 'ban.fp.def', 0.7); + assert.nestedPropertyVal(firstBid, 'ban.fp.cur', 'TRY'); + assert.deepNestedPropertyVal(firstBid, 'ban.fp.siz', [{w: 300, h: 600, p: 1.3}, {w: 160, h: 60, p: 2.5}]); + + assert.isTrue(getFloorStub1.calledThrice); + + assert.nestedPropertyVal(secondBid, 'ban.fp.def', 1.2); + assert.nestedPropertyVal(secondBid, 'ban.fp.cur', 'USD'); + assert.deepNestedPropertyVal(secondBid, 'ban.fp.siz', [{w: 728, h: 90, p: 1.85}]); + + assert.isTrue(getFloorStub2.calledTwice); + }); + + it('should add floor info to video bid request if floor is available', () => { + const bidReq = buildBidderRequest(); + + const getFloorStub1 = sinon.stub(); + const getFloorStub2 = sinon.stub(); + + getFloorStub1 + .returns({}) + .withArgs({currency: 'EUR', mediaType: 'video', size: '*'}) + .returns({currency: 'NZD', floor: 3.25}) + .withArgs({currency: 'EUR', mediaType: 'video', size: [640, 480]}) + .returns({currency: 'NZD', floor: 4.10}); + + getFloorStub2 + .returns({}) + .withArgs({currency: 'EUR', mediaType: 'video', size: '*'}) + .returns({currency: 'GBP', floor: 4.75}) + .withArgs({currency: 'EUR', mediaType: 'video', size: [1280, 720]}) + .returns({currency: 'GBP', floor: 6.50}) + + delete bidReq.bids[0].mediaTypes.banner; + bidReq.bids[0].mediaTypes.video = { + playerSize: [640, 480], + context: 'instream' + }; + + delete bidReq.bids[1].mediaTypes.banner; + bidReq.bids[1].mediaTypes.video = { + playerSize: [1280, 720], + context: 'outstream' + }; + + bidReq.bids[0].getFloor = getFloorStub1; + bidReq.bids[1].getFloor = getFloorStub2; + + const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq); + + const serverRequestBids = serverRequestInfo.data.bids; + const firstBid = serverRequestBids[0]; + const secondBid = serverRequestBids[1]; + + assert.nestedPropertyVal(firstBid, 'vid.fp.def', 3.25); + assert.nestedPropertyVal(firstBid, 'vid.fp.cur', 'NZD'); + assert.deepNestedPropertyVal(firstBid, 'vid.fp.siz', [{w: 640, h: 480, p: 4.10}]); + + assert.isTrue(getFloorStub1.calledTwice); + + assert.nestedPropertyVal(secondBid, 'vid.fp.def', 4.75); + assert.nestedPropertyVal(secondBid, 'vid.fp.cur', 'GBP'); + assert.deepNestedPropertyVal(secondBid, 'vid.fp.siz', [{w: 1280, h: 720, p: 6.50}]); + + assert.isTrue(getFloorStub2.calledTwice); + }); + + it('should not add floor info to bid request if floor is unavailable', () => { + const bidReq = buildBidderRequest(); + const getFloorSpy = sinon.spy(() => ({})); + + delete bidReq.bids[0].getFloor; + bidReq.bids[1].getFloor = getFloorSpy; + + const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq); + + const serverRequestBids = serverRequestInfo.data.bids; + const firstBid = serverRequestBids[0]; + const secondBid = serverRequestBids[1]; + + assert.nestedPropertyVal(firstBid, 'ban.fp', undefined); + assert.nestedPropertyVal(secondBid, 'ban.fp', undefined); + + assert.isTrue(getFloorSpy.calledWith({currency: 'EUR', mediaType: 'banner', size: '*'})); + assert.isTrue(getFloorSpy.calledWith({currency: 'EUR', mediaType: 'banner', size: [728, 90]})); + assert.isTrue(getFloorSpy.calledTwice); + }); + + it('should not add floor info for a size when it is the same as the default', () => { + const bidReq = buildBidderRequest(); + const getFloorStub = sinon.stub(); + + getFloorStub + .returns({currency: 'EUR', floor: 1.9}) + .withArgs({currency: 'EUR', mediaType: BANNER, size: [160, 60]}) + .returns({currency: 'EUR', floor: 2.7}); + + bidReq.bids[0].getFloor = getFloorStub; + + const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq); + + const serverRequestBids = serverRequestInfo.data.bids; + const bid = serverRequestBids[0]; + + assert.nestedPropertyVal(bid, 'ban.fp.def', 1.9); + assert.nestedPropertyVal(bid, 'ban.fp.cur', 'EUR'); + assert.deepNestedPropertyVal(bid, 'ban.fp.siz', [{w: 160, h: 60, p: 2.7}]); + }); }); }); }); diff --git a/test/spec/modules/weboramaRtdProvider_spec.js b/test/spec/modules/weboramaRtdProvider_spec.js index bbc1c6d6f02..7de8474d7c9 100644 --- a/test/spec/modules/weboramaRtdProvider_spec.js +++ b/test/spec/modules/weboramaRtdProvider_spec.js @@ -130,19 +130,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_ctx=foo;webo_ctx=bar;webo_ds=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_ctx=foo,bar|webo_ds=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -217,19 +217,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_vctx=foo;webo_vctx=bar'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_vctx=foo,bar'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -304,19 +304,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_vctx=foo;webo_vctx=bar'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_vctx=foo,bar'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -543,9 +543,22 @@ describe('weboramaRtdProvider', function() { expect(adUnit.bids[1].params).to.be.undefined; expect(adUnit.bids[2].params.keywords).to.deep.equal(data); expect(adUnit.bids[3].params).to.be.undefined; - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + + return; + } + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -809,9 +822,10 @@ describe('weboramaRtdProvider', function() { baz: 'bam', } }); - - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -951,9 +965,10 @@ describe('weboramaRtdProvider', function() { baz: 'bam', } }); - - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -1105,8 +1120,8 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar;webo_ctx=foo;webo_ctx=bar;webo_ds=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar|webo_ctx=foo,bar|webo_ds=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar'); expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ foo: ['bar'], webo_ctx: ['foo', 'bar'], @@ -1115,20 +1130,20 @@ describe('weboramaRtdProvider', function() { expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ inventory: { foo: 'bar', - webo_ctx: ['foo', 'bar'], - webo_ds: ['baz'], }, visitor: { baz: 'bam', } }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data - }, - } - }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) }); it('should use default profile in case of api error', function() { @@ -1196,19 +1211,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_ctx=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_ctx=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: defaultProfile - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: defaultProfile - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: defaultProfile + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: defaultProfile, meta: { @@ -1316,20 +1331,35 @@ describe('weboramaRtdProvider', function() { reqBidsConfigObj.adUnits.forEach(adUnit => { expect(adUnit.bids.length).to.equal(5); - expect(adUnit.bids[0].params.target).to.equal('webo_ctx=foo;webo_ctx=bar;webo_ds=baz'); - expect(adUnit.bids[1].params.dctr).to.equal('webo_ctx=foo,bar|webo_ds=baz'); - expect(adUnit.bids[3].params).to.deep.equal({ - inventory: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ + expect(adUnit.bids[0].params).to.be.undefined; + expect(adUnit.bids[1].params).to.be.undefined; + expect(adUnit.bids[3].params).to.be.undefined; + }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: { + webo_ctx: ['foo', 'bar'], + webo_ds: ['baz'], + webo_bar: ['baz'], + } + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ site: { ext: { data: data }, } }); - }); - + }) expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ webo_ctx: ['foo', 'bar'], webo_ds: ['baz'], @@ -1414,19 +1444,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_cs=foo;webo_cs=bar;webo_audiences=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_cs=foo,bar|webo_audiences=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - visitor: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - user: { - ext: { - data: data - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: data + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -1545,8 +1575,21 @@ describe('weboramaRtdProvider', function() { expect(adUnit.bids[2].params.keywords).to.deep.equal(data); expect(adUnit.bids[3].params).to.be.undefined; }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: data + }, + } + }); + + return + } + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -1657,7 +1700,21 @@ describe('weboramaRtdProvider', function() { expect(adUnit.bids[1].params).to.be.undefined; expect(adUnit.bids[3].params).to.be.undefined; }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: data + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); expect(reqBidsConfigObj.adUnits[1].bids[2].params).to.be.undefined; @@ -1813,7 +1870,9 @@ describe('weboramaRtdProvider', function() { } }); }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -1956,7 +2015,9 @@ describe('weboramaRtdProvider', function() { } }); }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -2109,8 +2170,8 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar;webo_cs=foo;webo_cs=bar;webo_audiences=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar|webo_cs=foo,bar|webo_audiences=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar'); expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ foo: ['bar'], webo_cs: ['foo', 'bar'], @@ -2122,17 +2183,17 @@ describe('weboramaRtdProvider', function() { }, visitor: { baz: 'bam', - webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], - } - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - user: { - ext: { - data: data - }, } }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: data + }, + } + }); + }) }); it('should use default profile in case of nothing on local storage', function() { @@ -2187,19 +2248,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_audiences=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_audiences=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - visitor: defaultProfile - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - user: { - ext: { - data: defaultProfile - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: defaultProfile + }, + } + }); + }) }); it('should use default profile if cant read from local storage', function() { @@ -2261,19 +2322,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_audiences=baz'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_audiences=baz'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - visitor: defaultProfile - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - user: { - ext: { - data: defaultProfile - }, - } - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: defaultProfile + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: defaultProfile, meta: { @@ -2383,26 +2444,35 @@ describe('weboramaRtdProvider', function() { reqBidsConfigObj.adUnits.forEach(adUnit => { expect(adUnit.bids.length).to.equal(5); - expect(adUnit.bids[0].params.target).to.equal('webo_cs=foo;webo_cs=bar;webo_audiences=baz'); - expect(adUnit.bids[1].params.dctr).to.equal('webo_cs=foo,bar|webo_audiences=baz'); - expect(adUnit.bids[3].params).to.deep.equal({ - visitor: data - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ + expect(adUnit.bids[0].params).to.be.undefined; + expect(adUnit.bids[1].params).to.be.undefined; + expect(adUnit.bids[3].params).to.be.undefined; + }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + user: { + ext: { + data: { + webo_cs: ['foo', 'bar'], + webo_audiences: ['baz'], + webo_bar: ['baz'], + } + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ user: { ext: { data: data }, } }); - }); - - expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ - webo_cs: ['foo', 'bar'], - webo_audiences: ['baz'], - webo_bar: ['baz'], - }); - expect(reqBidsConfigObj.adUnits[1].bids[2].params.keywords).to.deep.equal(data); + }) expect(onDataResponse).to.deep.equal({ data: data, @@ -2480,19 +2550,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('lite_occupation=gérant;lite_occupation=bénévole;lite_hobbies=sport;lite_hobbies=cinéma'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('lite_occupation=gérant,bénévole|lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: data, - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data, - }, - }, - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -2610,7 +2680,21 @@ describe('weboramaRtdProvider', function() { expect(adUnit.bids[2].params.keywords).to.deep.equal(data); expect(adUnit.bids[3].params).to.be.undefined; }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) expect(onDataResponse).to.deep.equal({ data: data, @@ -2721,11 +2805,26 @@ describe('weboramaRtdProvider', function() { expect(adUnit.bids[1].params).to.be.undefined; expect(adUnit.bids[3].params).to.be.undefined; }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); expect(reqBidsConfigObj.adUnits[1].bids[2].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) + expect(onDataResponse).to.deep.equal({ data: data, meta: { @@ -2876,7 +2975,9 @@ describe('weboramaRtdProvider', function() { } }); }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -3018,7 +3119,9 @@ describe('weboramaRtdProvider', function() { } }); }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.be.undefined; + }) }); }); }); @@ -3173,8 +3276,8 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar;lite_occupation=gérant;lite_occupation=bénévole;lite_hobbies=sport;lite_hobbies=cinéma'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar|lite_occupation=gérant,bénévole|lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('foo=bar'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('foo=bar'); expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ foo: ['bar'], lite_occupation: ['gérant', 'bénévole'], @@ -3183,20 +3286,20 @@ describe('weboramaRtdProvider', function() { expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ inventory: { foo: 'bar', - lite_occupation: ['gérant', 'bénévole'], - lite_hobbies: ['sport', 'cinéma'], }, visitor: { baz: 'bam', } }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data, - }, - }, - }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + }) }); it('should use default profile in case of nothing on local storage', function() { @@ -3250,19 +3353,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('lite_hobbies=sport;lite_hobbies=cinéma'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: defaultProfile, - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: defaultProfile, - }, - }, - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: defaultProfile + }, + } + }); + }) }); it('should use default profile if cant read from local storage', function() { @@ -3323,12 +3426,10 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('lite_hobbies=sport;lite_hobbies=cinéma'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: defaultProfile, - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ site: { ext: { @@ -3336,6 +3437,15 @@ describe('weboramaRtdProvider', function() { }, }, }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: defaultProfile, + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: defaultProfile, meta: { @@ -3403,19 +3513,19 @@ describe('weboramaRtdProvider', function() { }); expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('lite_hobbies=sport;lite_hobbies=cinéma'); - expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[0].params).to.be.undefined; + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.be.undefined; expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); - expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ - inventory: defaultProfile, - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: defaultProfile, - }, - }, - }); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.be.undefined; + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: defaultProfile + }, + } + }); + }) expect(onDataResponse).to.deep.equal({ data: defaultProfile, meta: { @@ -3523,19 +3633,35 @@ describe('weboramaRtdProvider', function() { reqBidsConfigObj.adUnits.forEach(adUnit => { expect(adUnit.bids.length).to.equal(5); - expect(adUnit.bids[0].params.target).to.equal('lite_occupation=gérant;lite_occupation=bénévole;lite_hobbies=sport;lite_hobbies=cinéma'); - expect(adUnit.bids[1].params.dctr).to.equal('lite_occupation=gérant,bénévole|lite_hobbies=sport,cinéma'); - expect(adUnit.bids[3].params).to.deep.equal({ - inventory: data, + expect(adUnit.bids[0].params).to.be.undefined; + expect(adUnit.bids[1].params).to.be.undefined; + expect(adUnit.bids[3].params).to.be.undefined; + }); + ['smartadserver', 'pubmatic', 'appnexus', 'rubicon', 'other'].forEach((v) => { + if (v == 'appnexus') { + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: { + lite_occupation: ['gérant', 'bénévole'], + lite_hobbies: ['sport', 'cinéma'], + lito_bar: ['baz'], + }, + }, + } + }); + + return + } + + expect(reqBidsConfigObj.ortb2Fragments.bidder[v]).to.deep.equal({ + site: { + ext: { + data: data, + }, + } }); - }); - expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ - site: { - ext: { - data: data, - }, - }, - }); + }) expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal({ lite_occupation: ['gérant', 'bénévole'], diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 80537facd41..93c231c816b 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -200,6 +200,15 @@ const NATIVE_RESPONSE = Object.assign({}, RESPONSE, { value: 'Native body value', }, }, + { + id: 4, + img: { + url: 'https://localhost:8080/assets/favicon/favicon-16x16.png', + w: 16, + h: 16, + type: 1, + }, + }, ], imptrackers: [ 'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12', @@ -567,15 +576,24 @@ describe('yieldlabBidAdapter', () => { expect(result[0].native.image.url).to.equal('https://localhost:8080/yl-logo100x100.jpg'); expect(result[0].native.image.width).to.equal(100); expect(result[0].native.image.height).to.equal(100); + expect(result[0].native.icon.url).to.equal('https://localhost:8080/assets/favicon/favicon-16x16.png'); + expect(result[0].native.icon.width).to.equal(16); + expect(result[0].native.icon.height).to.equal(16); expect(result[0].native.clickUrl).to.equal('https://www.yieldlab.de'); expect(result[0].native.impressionTrackers.length).to.equal(3); - expect(result[0].native.assets.length).to.equal(3); + expect(result[0].native.assets.length).to.equal(4); const titleAsset = result[0].native.assets.find(asset => 'title' in asset); - const imageAsset = result[0].native.assets.find(asset => 'img' in asset); + const imageAsset = result[0].native.assets.find((asset) => { + return asset?.img?.type === 3; + }); + const iconAsset = result[0].native.assets.find((asset) => { + return asset?.img?.type === 1; + }); const bodyAsset = result[0].native.assets.find(asset => 'data' in asset); expect(titleAsset).to.exist.and.to.have.nested.property('id', 1) expect(imageAsset).to.exist.and.to.have.nested.property('id', 2) expect(bodyAsset).to.exist.and.to.have.nested.property('id', 3) + expect(iconAsset).to.exist.and.to.have.nested.property('id', 4) }); it('should add adUrl and default native assets when type is Native', () => { @@ -601,6 +619,28 @@ describe('yieldlabBidAdapter', () => { expect(result[0].native.image.height).to.equal(0); }); + it('should not add icon if not present in the native response', () => { + const NATIVE_RESPONSE_WITHOUT_ICON = Object.assign({}, NATIVE_RESPONSE, { + native: { + link: { + url: 'https://www.yieldlab.de', + }, + assets: [ + { + id: 1, + title: { + text: 'This is a great headline', + } + } + ], + imptrackers: [], + }, + }); + const result = spec.interpretResponse({body: [NATIVE_RESPONSE_WITHOUT_ICON]}, {validBidRequests: [NATIVE_REQUEST()], queryParams: REQPARAMS}); + expect(result[0].native.hasOwnProperty('icon')).to.be.false; + expect(result[0].native.title).to.equal('This is a great headline'); + }); + it('should append gdpr parameters to vastUrl', () => { const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST()], queryParams: REQPARAMS_GDPR}); diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js index 28d7ba21de4..601f4546a29 100644 --- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js @@ -171,6 +171,87 @@ describe('Zeta Ssp Bid Adapter', function () { params: params }]; + const zetaResponse = { + body: { + id: '12345', + seatbid: [ + { + bid: [ + { + id: 'auctionId', + impid: 'impId', + price: 0.0, + adm: 'adMarkup', + crid: 'creativeId', + adomain: [ + 'https://example.com' + ], + h: 250, + w: 300 + } + ] + } + ], + cur: 'USD' + } + } + + const responseBannerPayload = { + data: { + id: '123', + site: { + id: 'SITE_ID', + page: 'page.com', + domain: 'domain.com' + }, + user: { + id: '45asdf9tydhrty789adfad4678rew656789', + buyeruid: '1234567890' + }, + cur: [ + 'USD' + ], + imp: [ + { + id: '1', + banner: { + h: 600, + w: 160 + } + } + ], + at: 1 + } + }; + + const responseVideoPayload = { + data: { + id: '123', + site: { + id: 'SITE_ID', + page: 'page.com', + domain: 'domain.com' + }, + user: { + id: '45asdf9tydhrty789adfad4678rew656789', + buyeruid: '1234567890' + }, + cur: [ + 'USD' + ], + imp: [ + { + id: '1', + video: { + h: 600, + w: 160 + } + } + ], + at: 1 + } + }; + it('Test the bid validation function', function () { const validBid = spec.isBidRequestValid(bannerRequest[0]); const invalidBid = spec.isBidRequestValid(null); @@ -224,7 +305,12 @@ describe('Zeta Ssp Bid Adapter', function () { 'https://example.com' ], h: 250, - w: 300 + w: 300, + ext: { + prebid: { + type: 'banner' + } + } }, { id: 'auctionId2', @@ -238,7 +324,9 @@ describe('Zeta Ssp Bid Adapter', function () { h: 150, w: 200, ext: { - bidtype: 'video' + prebid: { + type: 'video' + } } }, { @@ -251,7 +339,12 @@ describe('Zeta Ssp Bid Adapter', function () { 'https://example3.com' ], h: 400, - w: 300 + w: 300, + ext: { + prebid: { + type: 'video' + } + } } ] } @@ -260,7 +353,7 @@ describe('Zeta Ssp Bid Adapter', function () { } }; - const bidResponse = spec.interpretResponse(response, null); + const bidResponse = spec.interpretResponse(response, responseBannerPayload); expect(bidResponse).to.not.be.empty; const bid1 = bidResponse[0]; @@ -465,4 +558,50 @@ describe('Zeta Ssp Bid Adapter', function () { expect(payload.imp[0].banner.format[2].w).to.eql(100); expect(payload.imp[0].banner.format[2].h).to.eql(150); }); + + it('Test the response default mediaType:banner', function () { + const bidResponse = spec.interpretResponse(zetaResponse, responseBannerPayload); + expect(bidResponse).to.not.be.empty; + expect(bidResponse.length).to.eql(1); + expect(bidResponse[0].mediaType).to.eql(BANNER); + expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + expect(bidResponse[0].vastXml).to.be.undefined; + }); + + it('Test the response default mediaType:video', function () { + const bidResponse = spec.interpretResponse(zetaResponse, responseVideoPayload); + expect(bidResponse).to.not.be.empty; + expect(bidResponse.length).to.eql(1); + expect(bidResponse[0].mediaType).to.eql(VIDEO); + expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + }); + + it('Test the response mediaType:video from ext param', function () { + zetaResponse.body.seatbid[0].bid[0].ext = { + prebid: { + type: 'video' + } + } + const bidResponse = spec.interpretResponse(zetaResponse, responseBannerPayload); + expect(bidResponse).to.not.be.empty; + expect(bidResponse.length).to.eql(1); + expect(bidResponse[0].mediaType).to.eql(VIDEO); + expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + }); + + it('Test the response mediaType:banner from ext param', function () { + zetaResponse.body.seatbid[0].bid[0].ext = { + prebid: { + type: 'banner' + } + } + const bidResponse = spec.interpretResponse(zetaResponse, responseVideoPayload); + expect(bidResponse).to.not.be.empty; + expect(bidResponse.length).to.eql(1); + expect(bidResponse[0].mediaType).to.eql(BANNER); + expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm); + expect(bidResponse[0].vastXml).to.be.undefined; + }); });